From cef49eff228b7048c4707dac6dc389c4d8b24f75 Mon Sep 17 00:00:00 2001 From: Santiago Lezica Date: Fri, 29 Jan 2021 18:51:08 -0300 Subject: [PATCH] Release 2.0.0 --- blockchain_scanner.go | 280 -- cmd/survey/main.go | 51 + electrum/client.go | 392 +++ electrum/pool.go | 28 + go.mod | 13 +- go.sum | 57 +- keys_generator.go | 25 +- main.go | 50 +- scanner/scanner.go | 193 ++ scanner/servers.go | 97 + scanner/task.go | 180 ++ sweeper.go | 122 +- utils/logger.go | 53 + vendor/github.com/hhrutter/lzw/.gitignore | 6 + vendor/github.com/hhrutter/lzw/LICENSE | 27 + vendor/github.com/hhrutter/lzw/README.md | 37 + vendor/github.com/hhrutter/lzw/go.mod | 3 + vendor/github.com/hhrutter/lzw/reader.go | 238 ++ vendor/github.com/hhrutter/lzw/writer.go | 283 ++ vendor/github.com/hhrutter/tiff/.gitignore | 6 + vendor/github.com/hhrutter/tiff/LICENSE | 27 + vendor/github.com/hhrutter/tiff/README.md | 23 + vendor/github.com/hhrutter/tiff/buffer.go | 69 + vendor/github.com/hhrutter/tiff/compress.go | 58 + vendor/github.com/hhrutter/tiff/consts.go | 149 + vendor/github.com/hhrutter/tiff/go.mod | 8 + vendor/github.com/hhrutter/tiff/go.sum | 6 + vendor/github.com/hhrutter/tiff/reader.go | 735 +++++ vendor/github.com/hhrutter/tiff/writer.go | 482 +++ vendor/github.com/muun/libwallet/.gitignore | 1 + vendor/github.com/muun/libwallet/V1.go | 17 +- vendor/github.com/muun/libwallet/V2.go | 24 +- vendor/github.com/muun/libwallet/V3.go | 17 +- vendor/github.com/muun/libwallet/V4.go | 14 +- vendor/github.com/muun/libwallet/address.go | 27 +- .../github.com/muun/libwallet/addresses/v2.go | 6 +- .../github.com/muun/libwallet/addresses/v3.go | 4 +- .../github.com/muun/libwallet/addresses/v4.go | 4 +- .../muun/libwallet/aescbc/aescbc.go | 3 +- .../muun/libwallet/challenge_keys.go | 119 +- .../muun/libwallet/challenge_public_key.go | 4 +- .../muun/libwallet/emergency_kit.go | 123 +- .../muun/libwallet/emergencykit/content.go | 519 ++-- .../muun/libwallet/emergencykit/css.go | 296 +- .../libwallet/emergencykit/descriptors.go | 171 ++ .../libwallet/emergencykit/emergencykit.go | 95 +- .../muun/libwallet/emergencykit/metadata.go | 145 + vendor/github.com/muun/libwallet/encrypt.go | 79 +- vendor/github.com/muun/libwallet/errors.go | 22 + .../muun/libwallet/errors/errors.go | 28 + vendor/github.com/muun/libwallet/go.mod | 6 +- vendor/github.com/muun/libwallet/go.sum | 53 +- .../github.com/muun/libwallet/hdprivatekey.go | 11 +- .../github.com/muun/libwallet/hdpublickey.go | 30 +- .../muun/libwallet/incoming_swap.go | 10 +- vendor/github.com/muun/libwallet/invoice.go | 10 +- vendor/github.com/muun/libwallet/invoices.go | 78 +- .../libwallet/partiallysignedtransaction.go | 53 +- vendor/github.com/muun/libwallet/publickey.go | 5 +- .../libwallet/recoverycode/recoverycode.go | 8 +- vendor/github.com/muun/libwallet/segwit.go | 12 +- .../muun/libwallet/sphinx/sphinx.go | 11 +- .../muun/libwallet/submarineSwapV1.go | 8 +- .../muun/libwallet/submarineSwapV2.go | 8 +- vendor/github.com/muun/libwallet/swaps/v2.go | 3 +- .../muun/libwallet/walletdb/walletdb.go | 20 +- vendor/github.com/pdfcpu/pdfcpu/LICENSE.txt | 202 ++ .../pdfcpu/pdfcpu/internal/config/config.go | 7 + .../pdfcpu/pdfcpu/internal/config/config.yml | 37 + .../internal/corefont/metrics/metrics.go | 55 + .../internal/corefont/metrics/standard.go | 680 +++++ .../github.com/pdfcpu/pdfcpu/pkg/api/api.go | 169 + .../pdfcpu/pdfcpu/pkg/api/attach.go | 331 ++ .../github.com/pdfcpu/pdfcpu/pkg/api/boxes.go | 325 ++ .../pdfcpu/pdfcpu/pkg/api/collect.go | 104 + .../pdfcpu/pdfcpu/pkg/api/create.go | 34 + .../pdfcpu/pdfcpu/pkg/api/crypto.go | 66 + .../pdfcpu/pdfcpu/pkg/api/extract.go | 358 +++ .../github.com/pdfcpu/pdfcpu/pkg/api/fonts.go | 235 ++ .../pdfcpu/pdfcpu/pkg/api/importImage.go | 170 ++ .../github.com/pdfcpu/pdfcpu/pkg/api/info.go | 60 + .../pdfcpu/pdfcpu/pkg/api/keywords.go | 221 ++ .../github.com/pdfcpu/pdfcpu/pkg/api/merge.go | 198 ++ .../github.com/pdfcpu/pdfcpu/pkg/api/nup.go | 175 ++ .../pdfcpu/pdfcpu/pkg/api/optimize.go | 108 + .../github.com/pdfcpu/pdfcpu/pkg/api/pages.go | 253 ++ .../pdfcpu/pdfcpu/pkg/api/permissions.go | 168 + .../pdfcpu/pdfcpu/pkg/api/properties.go | 221 ++ .../pdfcpu/pdfcpu/pkg/api/rotate.go | 116 + .../pdfcpu/pdfcpu/pkg/api/selectPages.go | 651 ++++ .../github.com/pdfcpu/pdfcpu/pkg/api/split.go | 186 ++ .../github.com/pdfcpu/pdfcpu/pkg/api/stamp.go | 442 +++ .../github.com/pdfcpu/pdfcpu/pkg/api/trim.go | 109 + .../pdfcpu/pdfcpu/pkg/api/validate.go | 98 + .../pdfcpu/pdfcpu/pkg/filter/ascii85Decode.go | 76 + .../pdfcpu/pkg/filter/asciiHexDecode.go | 82 + .../pdfcpu/pdfcpu/pkg/filter/ccittDecode.go | 93 + .../pdfcpu/pdfcpu/pkg/filter/filter.go | 99 + .../pdfcpu/pdfcpu/pkg/filter/flateDecode.go | 335 ++ .../pdfcpu/pdfcpu/pkg/filter/lzwDecode.go | 82 + .../pdfcpu/pdfcpu/pkg/filter/paeth.go | 75 + .../pdfcpu/pkg/filter/runLengthDecode.go | 141 + .../pdfcpu/pdfcpu/pkg/font/install.go | 1022 +++++++ .../pdfcpu/pdfcpu/pkg/font/metrics.go | 307 ++ .../github.com/pdfcpu/pdfcpu/pkg/log/log.go | 239 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/array.go | 225 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/attach.go | 380 +++ .../pdfcpu/pdfcpu/pkg/pdfcpu/bookmarks.go | 145 + .../pdfcpu/pdfcpu/pkg/pdfcpu/boxes.go | 1211 ++++++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/collect.go | 39 + .../pdfcpu/pdfcpu/pkg/pdfcpu/colorSpace.go | 32 + .../pdfcpu/pdfcpu/pkg/pdfcpu/configuration.go | 344 +++ .../pdfcpu/pdfcpu/pkg/pdfcpu/context.go | 725 +++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/create.go | 862 ++++++ .../pdfcpu/pkg/pdfcpu/createAnnotations.go | 1204 ++++++++ .../pdfcpu/pkg/pdfcpu/createRenditions.go | 335 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/createTestPDF.go | 2006 ++++++++++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/crypto.go | 1519 +++++++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/date.go | 367 +++ .../pdfcpu/pdfcpu/pkg/pdfcpu/dict.go | 524 ++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/doc.go | 39 + .../pdfcpu/pdfcpu/pkg/pdfcpu/equal.go | 221 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/extract.go | 337 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/fontDict.go | 344 +++ .../pdfcpu/pdfcpu/pkg/pdfcpu/iccProfile.go | 311 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/importImage.go | 482 +++ .../pdfcpu/pdfcpu/pkg/pdfcpu/info.go | 380 +++ .../pdfcpu/pdfcpu/pkg/pdfcpu/keywords.go | 103 + .../pdfcpu/pdfcpu/pkg/pdfcpu/merge.go | 330 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/nameTree.go | 487 +++ .../pdfcpu/pdfcpu/pkg/pdfcpu/nup.go | 845 +++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/optimize.go | 1214 ++++++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/pages.go | 170 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/paperSize.go | 208 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/parse.go | 1003 ++++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/parseConfig.go | 118 + .../pdfcpu/pkg/pdfcpu/parseConfig_js.go | 209 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/parseContent.go | 365 +++ .../pdfcpu/pdfcpu/pkg/pdfcpu/properties.go | 89 + .../pdfcpu/pdfcpu/pkg/pdfcpu/read.go | 2579 ++++++++++++++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/readImage.go | 399 +++ .../pdfcpu/pdfcpu/pkg/pdfcpu/renderImage.go | 803 +++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/resources.go | 172 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/rotate.go | 49 + .../pdfcpu/pdfcpu/pkg/pdfcpu/slice.go | 37 + .../pdfcpu/pdfcpu/pkg/pdfcpu/stamp.go | 2389 +++++++++++++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/stats.go | 133 + .../pdfcpu/pdfcpu/pkg/pdfcpu/streamdict.go | 312 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/string.go | 250 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/types.go | 502 +++ .../pdfcpu/pdfcpu/pkg/pdfcpu/utf16.go | 167 + .../pdfcpu/pkg/pdfcpu/validate/acroForm.go | 484 +++ .../pdfcpu/pkg/pdfcpu/validate/action.go | 929 ++++++ .../pdfcpu/pkg/pdfcpu/validate/annotations.go | 1617 ++++++++++ .../pdfcpu/pkg/pdfcpu/validate/colorspace.go | 641 ++++ .../pdfcpu/pkg/pdfcpu/validate/destination.go | 156 + .../pdfcpu/pkg/pdfcpu/validate/extGState.go | 866 ++++++ .../pdfcpu/pkg/pdfcpu/validate/fileSpec.go | 501 +++ .../pdfcpu/pdfcpu/pkg/pdfcpu/validate/font.go | 1014 ++++++ .../pdfcpu/pkg/pdfcpu/validate/function.go | 239 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/validate/info.go | 202 ++ .../pdfcpu/pkg/pdfcpu/validate/media.go | 1047 +++++++ .../pdfcpu/pkg/pdfcpu/validate/nameTree.go | 756 +++++ .../pdfcpu/pkg/pdfcpu/validate/numberTree.go | 207 ++ .../pdfcpu/pkg/pdfcpu/validate/objects.go | 1601 ++++++++++ .../pkg/pdfcpu/validate/optionalContent.go | 456 +++ .../pdfcpu/pkg/pdfcpu/validate/outlineTree.go | 172 ++ .../pdfcpu/pkg/pdfcpu/validate/pages.go | 1011 ++++++ .../pdfcpu/pkg/pdfcpu/validate/pattern.go | 179 ++ .../pdfcpu/pkg/pdfcpu/validate/properties.go | 128 + .../pdfcpu/pkg/pdfcpu/validate/shading.go | 351 +++ .../pdfcpu/pkg/pdfcpu/validate/structTree.go | 688 +++++ .../pdfcpu/pkg/pdfcpu/validate/thread.go | 249 ++ .../pdfcpu/pkg/pdfcpu/validate/xObject.go | 872 ++++++ .../pdfcpu/pkg/pdfcpu/validate/xReftable.go | 919 ++++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/version.go | 71 + .../pdfcpu/pdfcpu/pkg/pdfcpu/write.go | 987 ++++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/writeObjects.go | 734 +++++ .../pdfcpu/pdfcpu/pkg/pdfcpu/writePages.go | 283 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/writeStats.go | 266 ++ .../pdfcpu/pdfcpu/pkg/pdfcpu/xreftable.go | 2369 ++++++++++++++ .../pdfcpu/pdfcpu/pkg/types/types.go | 84 + vendor/golang.org/x/image/AUTHORS | 3 + vendor/golang.org/x/image/CONTRIBUTORS | 3 + vendor/golang.org/x/image/LICENSE | 27 + vendor/golang.org/x/image/PATENTS | 22 + vendor/golang.org/x/image/ccitt/reader.go | 795 +++++ vendor/golang.org/x/image/ccitt/table.go | 972 ++++++ vendor/golang.org/x/image/ccitt/writer.go | 102 + vendor/gopkg.in/yaml.v2/.travis.yml | 16 + vendor/gopkg.in/yaml.v2/LICENSE | 201 ++ vendor/gopkg.in/yaml.v2/LICENSE.libyaml | 31 + vendor/gopkg.in/yaml.v2/NOTICE | 13 + vendor/gopkg.in/yaml.v2/README.md | 133 + vendor/gopkg.in/yaml.v2/apic.go | 740 +++++ vendor/gopkg.in/yaml.v2/decode.go | 815 +++++ vendor/gopkg.in/yaml.v2/emitterc.go | 1685 ++++++++++ vendor/gopkg.in/yaml.v2/encode.go | 390 +++ vendor/gopkg.in/yaml.v2/go.mod | 5 + vendor/gopkg.in/yaml.v2/parserc.go | 1095 +++++++ vendor/gopkg.in/yaml.v2/readerc.go | 412 +++ vendor/gopkg.in/yaml.v2/resolve.go | 258 ++ vendor/gopkg.in/yaml.v2/scannerc.go | 2711 +++++++++++++++++ vendor/gopkg.in/yaml.v2/sorter.go | 113 + vendor/gopkg.in/yaml.v2/writerc.go | 26 + vendor/gopkg.in/yaml.v2/yaml.go | 466 +++ vendor/gopkg.in/yaml.v2/yamlh.go | 739 +++++ vendor/gopkg.in/yaml.v2/yamlprivateh.go | 173 ++ vendor/modules.txt | 21 +- 209 files changed, 70157 insertions(+), 926 deletions(-) delete mode 100644 blockchain_scanner.go create mode 100644 cmd/survey/main.go create mode 100644 electrum/client.go create mode 100644 electrum/pool.go create mode 100644 scanner/scanner.go create mode 100644 scanner/servers.go create mode 100644 scanner/task.go create mode 100644 utils/logger.go create mode 100644 vendor/github.com/hhrutter/lzw/.gitignore create mode 100644 vendor/github.com/hhrutter/lzw/LICENSE create mode 100644 vendor/github.com/hhrutter/lzw/README.md create mode 100644 vendor/github.com/hhrutter/lzw/go.mod create mode 100644 vendor/github.com/hhrutter/lzw/reader.go create mode 100644 vendor/github.com/hhrutter/lzw/writer.go create mode 100644 vendor/github.com/hhrutter/tiff/.gitignore create mode 100644 vendor/github.com/hhrutter/tiff/LICENSE create mode 100644 vendor/github.com/hhrutter/tiff/README.md create mode 100644 vendor/github.com/hhrutter/tiff/buffer.go create mode 100644 vendor/github.com/hhrutter/tiff/compress.go create mode 100644 vendor/github.com/hhrutter/tiff/consts.go create mode 100644 vendor/github.com/hhrutter/tiff/go.mod create mode 100644 vendor/github.com/hhrutter/tiff/go.sum create mode 100644 vendor/github.com/hhrutter/tiff/reader.go create mode 100644 vendor/github.com/hhrutter/tiff/writer.go create mode 100644 vendor/github.com/muun/libwallet/emergencykit/descriptors.go create mode 100644 vendor/github.com/muun/libwallet/emergencykit/metadata.go create mode 100644 vendor/github.com/muun/libwallet/errors.go create mode 100644 vendor/github.com/muun/libwallet/errors/errors.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/LICENSE.txt create mode 100644 vendor/github.com/pdfcpu/pdfcpu/internal/config/config.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/internal/config/config.yml create mode 100644 vendor/github.com/pdfcpu/pdfcpu/internal/corefont/metrics/metrics.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/internal/corefont/metrics/standard.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/api.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/attach.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/boxes.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/collect.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/create.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/crypto.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/extract.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/fonts.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/importImage.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/info.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/keywords.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/merge.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/nup.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/optimize.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/pages.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/permissions.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/properties.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/rotate.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/selectPages.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/split.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/stamp.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/trim.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/api/validate.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/filter/ascii85Decode.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/filter/asciiHexDecode.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/filter/ccittDecode.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/filter/filter.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/filter/flateDecode.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/filter/lzwDecode.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/filter/paeth.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/filter/runLengthDecode.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/font/install.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/font/metrics.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/log/log.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/array.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/attach.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/bookmarks.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/boxes.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/collect.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/colorSpace.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/configuration.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/context.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/create.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/createAnnotations.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/createRenditions.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/createTestPDF.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/crypto.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/date.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/dict.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/doc.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/equal.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/extract.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/fontDict.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/iccProfile.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/importImage.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/info.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/keywords.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/merge.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/nameTree.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/nup.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/optimize.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/pages.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/paperSize.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parse.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parseConfig.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parseConfig_js.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parseContent.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/properties.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/read.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/readImage.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/renderImage.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/resources.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/rotate.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/slice.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/stamp.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/stats.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/streamdict.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/string.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/utf16.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/acroForm.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/action.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/annotations.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/colorspace.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/destination.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/extGState.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/fileSpec.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/font.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/function.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/info.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/media.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/nameTree.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/numberTree.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/objects.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/optionalContent.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/outlineTree.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/pages.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/pattern.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/properties.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/shading.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/structTree.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/thread.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/xObject.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/xReftable.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/version.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/write.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/writeObjects.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/writePages.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/writeStats.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/xreftable.go create mode 100644 vendor/github.com/pdfcpu/pdfcpu/pkg/types/types.go create mode 100644 vendor/golang.org/x/image/AUTHORS create mode 100644 vendor/golang.org/x/image/CONTRIBUTORS create mode 100644 vendor/golang.org/x/image/LICENSE create mode 100644 vendor/golang.org/x/image/PATENTS create mode 100644 vendor/golang.org/x/image/ccitt/reader.go create mode 100644 vendor/golang.org/x/image/ccitt/table.go create mode 100644 vendor/golang.org/x/image/ccitt/writer.go create mode 100644 vendor/gopkg.in/yaml.v2/.travis.yml create mode 100644 vendor/gopkg.in/yaml.v2/LICENSE create mode 100644 vendor/gopkg.in/yaml.v2/LICENSE.libyaml create mode 100644 vendor/gopkg.in/yaml.v2/NOTICE create mode 100644 vendor/gopkg.in/yaml.v2/README.md create mode 100644 vendor/gopkg.in/yaml.v2/apic.go create mode 100644 vendor/gopkg.in/yaml.v2/decode.go create mode 100644 vendor/gopkg.in/yaml.v2/emitterc.go create mode 100644 vendor/gopkg.in/yaml.v2/encode.go create mode 100644 vendor/gopkg.in/yaml.v2/go.mod create mode 100644 vendor/gopkg.in/yaml.v2/parserc.go create mode 100644 vendor/gopkg.in/yaml.v2/readerc.go create mode 100644 vendor/gopkg.in/yaml.v2/resolve.go create mode 100644 vendor/gopkg.in/yaml.v2/scannerc.go create mode 100644 vendor/gopkg.in/yaml.v2/sorter.go create mode 100644 vendor/gopkg.in/yaml.v2/writerc.go create mode 100644 vendor/gopkg.in/yaml.v2/yaml.go create mode 100644 vendor/gopkg.in/yaml.v2/yamlh.go create mode 100644 vendor/gopkg.in/yaml.v2/yamlprivateh.go diff --git a/blockchain_scanner.go b/blockchain_scanner.go deleted file mode 100644 index 71ee344..0000000 --- a/blockchain_scanner.go +++ /dev/null @@ -1,280 +0,0 @@ -package main - -import ( - "fmt" - "os" - "path/filepath" - "time" - - "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcd/txscript" - - "github.com/btcsuite/btcd/btcjson" - "github.com/btcsuite/btcd/wire" - - "github.com/btcsuite/btclog" - - "github.com/btcsuite/btcd/rpcclient" - - "github.com/btcsuite/btcutil" - - _ "github.com/btcsuite/btcwallet/chain" - "github.com/btcsuite/btcwallet/walletdb" - _ "github.com/btcsuite/btcwallet/walletdb/bdb" - - "github.com/btcsuite/btcd/chaincfg" - - "github.com/lightninglabs/neutrino" - "github.com/lightninglabs/neutrino/headerfs" -) - -// RelevantTx contains a PKScipt, an Address an a boolean to check if its spent or not -type RelevantTx struct { - PkScript []byte - Address string - Spent bool - Satoshis int64 - SigningDetails signingDetails - Outpoint wire.OutPoint -} - -func (tx *RelevantTx) String() string { - return fmt.Sprintf("outpoint %v:%v for %v sats on path %v", - tx.Outpoint.Hash, tx.Outpoint.Index, tx.Satoshis, tx.SigningDetails.Address.DerivationPath()) -} - -var ( - chainParams = chaincfg.MainNetParams - bitcoinGenesisDate = chainParams.GenesisBlock.Header.Timestamp -) - -var relevantTxs = make(map[wire.OutPoint]*RelevantTx) -var rescan *neutrino.Rescan - -// TODO: Add signing details to the watchAddresses map -var watchAddresses = make(map[string]signingDetails) - -func startRescan(chainService *neutrino.ChainService, addrs map[string]signingDetails, birthday int) []*RelevantTx { - watchAddresses = addrs - - // Wait till we know where the tip is - for !chainService.IsCurrent() { - } - bestBlock, _ := chainService.BestBlock() - - startHeight := findStartHeight(birthday, chainService) - fmt.Println() - fmt.Printf("Starting at height %v", startHeight.Height) - fmt.Println() - - ntfn := rpcclient.NotificationHandlers{ - OnBlockConnected: func(hash *chainhash.Hash, height int32, t time.Time) { - totalDif := bestBlock.Height - startHeight.Height - currentDif := height - startHeight.Height - progress := (float64(currentDif) / float64(totalDif)) * 100.0 - progressBar := "" - numberOfBars := int(progress / 5) - for index := 0; index <= 20; index++ { - if index <= numberOfBars { - progressBar += "■" - } else { - progressBar += "□" - } - } - - fmt.Printf("\rProgress: [%v] %.2f%%. Scanning block %v of %v.", progressBar, progress, currentDif, totalDif) - }, - OnRedeemingTx: func(tx *btcutil.Tx, details *btcjson.BlockDetails) { - for _, input := range tx.MsgTx().TxIn { - outpoint := input.PreviousOutPoint - if _, ok := relevantTxs[outpoint]; ok { - relevantTxs[outpoint].Spent = true - } - } - }, - OnRecvTx: func(tx *btcutil.Tx, details *btcjson.BlockDetails) { - checkOutpoints(tx, details.Height) - }, - } - - rescan = neutrino.NewRescan( - &neutrino.RescanChainSource{ - ChainService: chainService, - }, - neutrino.WatchAddrs(buildAddresses()...), - neutrino.NotificationHandlers(ntfn), - neutrino.StartBlock(startHeight), - neutrino.EndBlock(bestBlock), - ) - errorChan := rescan.Start() - rescan.WaitForShutdown() - if err := <-errorChan; err != nil { - panic(err) - } - - return buildUtxos() -} - -func startChainService() (*neutrino.ChainService, func(), error) { - setUpLogger() - - dir := os.TempDir() - dirFolder := filepath.Join(dir, "muunRecoveryTool") - os.RemoveAll(dirFolder) - os.MkdirAll(dirFolder, 0700) - dbPath := filepath.Join(dirFolder, "neutrino.db") - - db, err := walletdb.Open("bdb", dbPath, true) - if err == walletdb.ErrDbDoesNotExist { - db, err = walletdb.Create("bdb", dbPath, true) - if err != nil { - panic(err) - } - } - - peers := make([]string, 1) - peers[0] = "btcd-mainnet.lightning.computer" - chainService, err := neutrino.NewChainService(neutrino.Config{ - DataDir: dirFolder, - Database: db, - ChainParams: chainParams, - ConnectPeers: peers, - AddPeers: peers, - }) - if err != nil { - panic(err) - } - - err = chainService.Start() - if err != nil { - panic(err) - } - - close := func() { - db.Close() - err := chainService.Stop() - if err != nil { - panic(err) - } - os.Remove(dbPath) - os.RemoveAll(dirFolder) - } - return chainService, close, err -} - -func findStartHeight(birthday int, chain *neutrino.ChainService) *headerfs.BlockStamp { - if birthday == 0 { - return &headerfs.BlockStamp{} - } - - const ( - // birthdayBlockDelta is the maximum time delta allowed between our - // birthday timestamp and our birthday block's timestamp when searching - // for a better birthday block candidate (if possible). - birthdayBlockDelta = 2 * time.Hour - ) - - birthtime := bitcoinGenesisDate.Add(time.Duration(birthday-2) * 24 * time.Hour) - - block, _ := chain.BestBlock() - - startHeight := int32(0) - bestHeight := block.Height - - left, right := startHeight, bestHeight - - for { - mid := left + (right-left)/2 - hash, _ := chain.GetBlockHash(int64(mid)) - header, _ := chain.GetBlockHeader(hash) - - // If the search happened to reach either of our range extremes, - // then we'll just use that as there's nothing left to search. - if mid == startHeight || mid == bestHeight || mid == left { - return &headerfs.BlockStamp{ - Hash: *hash, - Height: mid, - Timestamp: header.Timestamp, - } - } - - // The block's timestamp is more than 2 hours after the - // birthday, so look for a lower block. - if header.Timestamp.Sub(birthtime) > birthdayBlockDelta { - right = mid - continue - } - - // The birthday is more than 2 hours before the block's - // timestamp, so look for a higher block. - if header.Timestamp.Sub(birthtime) < -birthdayBlockDelta { - left = mid - continue - } - - return &headerfs.BlockStamp{ - Hash: *hash, - Height: mid, - Timestamp: header.Timestamp, - } - } -} - -func checkOutpoints(tx *btcutil.Tx, height int32) { - // Loop in the output addresses - for index, output := range tx.MsgTx().TxOut { - _, addrs, _, _ := txscript.ExtractPkScriptAddrs(output.PkScript, &chainParams) - for _, addr := range addrs { - // If one of the output addresses is in our Watch Addresses map, we try to add it to our relevant tx model - if _, ok := watchAddresses[addr.EncodeAddress()]; ok { - hash := tx.Hash() - relevantTx := &RelevantTx{ - PkScript: output.PkScript, - Address: addr.String(), - Spent: false, - Satoshis: output.Value, - SigningDetails: watchAddresses[addr.EncodeAddress()], - Outpoint: wire.OutPoint{ - Hash: *hash, - Index: uint32(index), - }, - } - - if _, ok := relevantTxs[relevantTx.Outpoint]; ok { - // If its already there we dont need to do anything - return - } - - relevantTxs[relevantTx.Outpoint] = relevantTx - } - } - } -} - -func buildUtxos() []*RelevantTx { - var utxos []*RelevantTx - for _, output := range relevantTxs { - if !output.Spent { - utxos = append(utxos, output) - } - } - return utxos -} - -func buildAddresses() []btcutil.Address { - addresses := make([]btcutil.Address, 0, len(watchAddresses)) - for addr := range watchAddresses { - address, err := btcutil.DecodeAddress(addr, &chainParams) - if err != nil { - panic(err) - } - addresses = append(addresses, address) - } - return addresses -} - -func setUpLogger() { - logger := btclog.NewBackend(os.Stdout).Logger("MUUN") - logger.SetLevel(btclog.LevelOff) - neutrino.UseLogger(logger) -} diff --git a/cmd/survey/main.go b/cmd/survey/main.go new file mode 100644 index 0000000..c327203 --- /dev/null +++ b/cmd/survey/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" + + "github.com/muun/recovery/electrum" + "github.com/muun/recovery/scanner" +) + +var failedToConnect []string +var withBatching []string +var withoutBatching []string + +func main() { + client := electrum.NewClient() + + for _, server := range scanner.PublicElectrumServers { + surveyServer(client, server) + } + + fmt.Println("// With batch support:") + for _, server := range withBatching { + fmt.Printf("\"%s\"\n", server) + } + + fmt.Println("// Without batch support:") + for _, server := range withoutBatching { + fmt.Printf("\"%s\"\n", server) + } + + fmt.Println("// Unclassified:") + for _, server := range failedToConnect { + fmt.Printf("\"%s\"\n", server) + } +} + +func surveyServer(client *electrum.Client, server string) { + fmt.Println("Surveyng", server) + err := client.Connect(server) + + if err != nil { + failedToConnect = append(failedToConnect, server) + return + } + + if client.SupportsBatching() { + withBatching = append(withBatching, server) + } else { + withoutBatching = append(withoutBatching, server) + } +} diff --git a/electrum/client.go b/electrum/client.go new file mode 100644 index 0000000..6e165a2 --- /dev/null +++ b/electrum/client.go @@ -0,0 +1,392 @@ +package electrum + +import ( + "bufio" + "crypto/sha256" + "crypto/tls" + "encoding/hex" + "encoding/json" + "fmt" + "net" + "sort" + "strings" + "time" + + "github.com/muun/recovery/utils" +) + +const defaultLoggerTag = "Electrum/?" +const connectionTimeout = time.Second * 10 +const messageDelim = byte('\n') + +var implsWithBatching = []string{"ElectrumX"} + +// Client is a TLS client that implements a subset of the Electrum protocol. +// +// It includes a minimal implementation of a JSON-RPC client, since the one provided by the +// standard library doesn't support features such as batching. +// +// It is absolutely not thread-safe. Every Client should have a single owner. +type Client struct { + Server string + ServerImpl string + ProtoVersion string + nextRequestID int + conn net.Conn + log *utils.Logger +} + +// Request models the structure of all Electrum protocol requests. +type Request struct { + ID int `json:"id"` + Method string `json:"method"` + Params []Param `json:"params"` +} + +// ErrorResponse models the structure of a generic error response. +type ErrorResponse struct { + ID int `json:"id"` + Error interface{} `json:"error"` // type varies among Electrum implementations. +} + +// ServerVersionResponse models the structure of a `server.version` response. +type ServerVersionResponse struct { + ID int `json:"id"` + Result []string `json:"result"` +} + +// ListUnspentResponse models a `blockchain.scripthash.listunspent` response. +type ListUnspentResponse struct { + ID int `json:"id"` + Result []UnspentRef `json:"result"` +} + +// BroadcastResponse models the structure of a `blockchain.transaction.broadcast` response. +type BroadcastResponse struct { + ID int `json:"id"` + Result string `json:"result"` +} + +// UnspentRef models an item in the `ListUnspentResponse` results. +type UnspentRef struct { + TxHash string `json:"tx_hash"` + TxPos int `json:"tx_pos"` + Value int `json:"value"` + Height int `json:"height"` +} + +// Param is a convenience type that models an item in the `Params` array of an Request. +type Param = interface{} + +// NewClient creates an initialized Client instance. +func NewClient() *Client { + return &Client{ + log: utils.NewLogger(defaultLoggerTag), + } +} + +// Connect establishes a TLS connection to an Electrum server. +func (c *Client) Connect(server string) error { + c.Disconnect() + + c.log.SetTag("Electrum/" + server) + c.Server = server + + c.log.Printf("Connecting") + + err := c.establishConnection() + if err != nil { + c.Disconnect() + return c.log.Errorf("Connect failed: %w", err) + } + + // Before calling it a day send a test request (trust me), and as we do identify the server: + err = c.identifyServer() + if err != nil { + c.Disconnect() + return c.log.Errorf("Identifying server failed: %w", err) + } + + c.log.Printf("Identified as %s (%s)", c.ServerImpl, c.ProtoVersion) + + return nil +} + +// Disconnect cuts the connection (if connected) to the Electrum server. +func (c *Client) Disconnect() error { + if c.conn == nil { + return nil + } + + c.log.Printf("Disconnecting") + + err := c.conn.Close() + if err != nil { + return c.log.Errorf("Disconnect failed: %w", err) + } + + c.conn = nil + return nil +} + +// SupportsBatching returns whether this client can process batch requests. +func (c *Client) SupportsBatching() bool { + for _, implName := range implsWithBatching { + if strings.HasPrefix(c.ServerImpl, implName) { + return true + } + } + + return false +} + +// ServerVersion calls the `server.version` method and returns the [impl, protocol version] tuple. +func (c *Client) ServerVersion() ([]string, error) { + request := Request{ + Method: "server.version", + Params: []Param{}, + } + + var response ServerVersionResponse + + err := c.call(&request, &response) + if err != nil { + return nil, c.log.Errorf("ServerVersion failed: %w", err) + } + + return response.Result, nil +} + +// Broadcast calls the `blockchain.transaction.broadcast` endpoint and returns the transaction hash. +func (c *Client) Broadcast(rawTx string) (string, error) { + request := Request{ + Method: "blockchain.transaction.broadcast", + Params: []Param{rawTx}, + } + + var response BroadcastResponse + + err := c.call(&request, &response) + if err != nil { + return "", c.log.Errorf("Broadcast failed: %w", err) + } + + return response.Result, nil +} + +// ListUnspent calls `blockchain.scripthash.listunspent` and returns the UTXO results. +func (c *Client) ListUnspent(indexHash string) ([]UnspentRef, error) { + request := Request{ + Method: "blockchain.scripthash.listunspent", + Params: []Param{indexHash}, + } + var response ListUnspentResponse + + err := c.call(&request, &response) + if err != nil { + return nil, c.log.Errorf("ListUnspent failed: %w", err) + } + + return response.Result, nil +} + +// ListUnspentBatch is like `ListUnspent`, but using batching. +func (c *Client) ListUnspentBatch(indexHashes []string) ([][]UnspentRef, error) { + requests := make([]*Request, len(indexHashes)) + + for i, indexHash := range indexHashes { + requests[i] = &Request{ + Method: "blockchain.scripthash.listunspent", + Params: []Param{indexHash}, + } + } + + var responses []ListUnspentResponse + + err := c.callBatch(requests, &responses) + if err != nil { + return nil, fmt.Errorf("ListUnspentBatch failed: %w", err) + } + + // Don't forget to sort responses: + sort.Slice(responses, func(i, j int) bool { + return responses[i].ID < responses[j].ID + }) + + // Now we can collect all results: + var unspentRefs [][]UnspentRef + + for _, response := range responses { + unspentRefs = append(unspentRefs, response.Result) + } + + return unspentRefs, nil +} + +func (c *Client) establishConnection() error { + // TODO: check if insecure is necessary + config := &tls.Config{ + InsecureSkipVerify: true, + } + + dialer := &net.Dialer{ + Timeout: connectionTimeout, + } + + conn, err := tls.DialWithDialer(dialer, "tcp", c.Server, config) + if err != nil { + return err + } + + c.conn = conn + return nil +} + +func (c *Client) identifyServer() error { + serverVersion, err := c.ServerVersion() + if err != nil { + return err + } + + c.ServerImpl = serverVersion[0] + c.ProtoVersion = serverVersion[1] + + c.log.Printf("Identified %s %s", c.ServerImpl, c.ProtoVersion) + + return nil +} + +// IsConnected returns whether this client is connected to a server. +// It does not guarantee the next request will succeed. +func (c *Client) IsConnected() bool { + return c.conn != nil +} + +// call executes a request with JSON marshalling, and loads the response into a pointer. +func (c *Client) call(request *Request, response interface{}) error { + // Assign a fresh request ID: + request.ID = c.incRequestID() + + // Serialize the request: + requestBytes, err := json.Marshal(request) + if err != nil { + return c.log.Errorf("Marshal failed %v: %w", request, err) + } + + // Make the call, obtain the serialized response: + responseBytes, err := c.callRaw(requestBytes) + if err != nil { + return c.log.Errorf("Send failed %s: %w", string(requestBytes), err) + } + + // Deserialize into an error, to see if there's any: + var maybeErrorResponse ErrorResponse + + err = json.Unmarshal(responseBytes, &maybeErrorResponse) + if err != nil { + return c.log.Errorf("Unmarshal of potential error failed: %s %w", string(responseBytes), err) + } + + if maybeErrorResponse.Error != nil { + return c.log.Errorf("Electrum error: %v", maybeErrorResponse.Error) + } + + // Deserialize the response: + err = json.Unmarshal(responseBytes, response) + if err != nil { + return c.log.Errorf("Unmarshal failed %s: %w", string(responseBytes), err) + } + + return nil +} + +// call executes a batch request with JSON marshalling, and loads the response into a pointer. +// Response may not match request order, so callers MUST sort them by ID. +func (c *Client) callBatch(requests []*Request, response interface{}) error { + // Assign fresh request IDs: + for _, request := range requests { + request.ID = c.incRequestID() + } + + // Serialize the request: + requestBytes, err := json.Marshal(requests) + if err != nil { + return c.log.Errorf("Marshal failed %v: %w", requests, err) + } + + // Make the call, obtain the serialized response: + responseBytes, err := c.callRaw(requestBytes) + if err != nil { + return c.log.Errorf("Send failed %s: %w", string(requestBytes), err) + } + + // Deserialize into an array of errors, to see if there's any: + var maybeErrorResponses []ErrorResponse + + err = json.Unmarshal(responseBytes, &maybeErrorResponses) + if err != nil { + return c.log.Errorf("Unmarshal of potential error failed: %s %w", string(responseBytes), err) + } + + // Walk the responses, returning the first error found: + for _, maybeErrorResponse := range maybeErrorResponses { + if maybeErrorResponse.Error != nil { + return c.log.Errorf("Electrum error: %v", maybeErrorResponse.Error) + } + } + + // Deserialize the response: + err = json.Unmarshal(responseBytes, response) + if err != nil { + return c.log.Errorf("Unmarshal failed %s: %w", string(responseBytes), err) + } + + return nil +} + +// callRaw sends a raw request in bytes, and returns a raw response (or an error). +func (c *Client) callRaw(request []byte) ([]byte, error) { + c.log.Printf("Sending %s", string(request)) + + if !c.IsConnected() { + return nil, c.log.Errorf("Send failed %s: not connected", string(request)) + } + + request = append(request, messageDelim) + + _, err := c.conn.Write(request) + if err != nil { + return nil, c.log.Errorf("Send failed %s: %w", string(request), err) + } + + reader := bufio.NewReader(c.conn) + + response, err := reader.ReadBytes(messageDelim) + if err != nil { + return nil, c.log.Errorf("Receive failed: %w", err) + } + + c.log.Printf("Received %s", string(response)) + + return response, nil +} + +func (c *Client) incRequestID() int { + c.nextRequestID++ + return c.nextRequestID +} + +// GetIndexHash returns the script parameter to use with Electrum, given a Bitcoin address. +func GetIndexHash(script []byte) string { + indexHash := sha256.Sum256(script) + reverse(&indexHash) + + return hex.EncodeToString(indexHash[:]) +} + +// reverse the order of the provided byte array, in place. +func reverse(a *[32]byte) { + for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 { + a[i], a[j] = a[j], a[i] + } +} diff --git a/electrum/pool.go b/electrum/pool.go new file mode 100644 index 0000000..d728bb3 --- /dev/null +++ b/electrum/pool.go @@ -0,0 +1,28 @@ +package electrum + +// Pool provides a shared pool of Clients that callers can acquire and release, limiting +// the amount of concurrent Clients in active use. +type Pool struct { + nextClient chan *Client +} + +// NewPool creates an initialized Pool with a `size` number of clients. +func NewPool(size int) *Pool { + nextClient := make(chan *Client, size) + + for i := 0; i < size; i++ { + nextClient <- NewClient() + } + + return &Pool{nextClient} +} + +// Acquire obtains an unused Client, blocking until one is released. +func (p *Pool) Acquire() <-chan *Client { + return p.nextClient +} + +// Release returns a Client to the pool, unblocking the next caller trying to `Acquire()`. +func (p *Pool) Release(client *Client) { + p.nextClient <- client +} diff --git a/go.mod b/go.mod index 0a9b04f..b886fb4 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,15 @@ -module github.com/muun/recovery_tool +module github.com/muun/recovery go 1.12 require ( github.com/btcsuite/btcd v0.21.0-beta - github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f + github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect github.com/btcsuite/btcutil v1.0.2 - github.com/btcsuite/btcwallet v0.11.1-0.20200612012534-48addcd5591a - github.com/btcsuite/btcwallet/walletdb v1.3.3 - github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200 - github.com/muun/libwallet v0.5.0 - github.com/pkg/errors v0.9.1 // indirect + github.com/btcsuite/btcwallet v0.11.1-0.20200612012534-48addcd5591a // indirect + github.com/btcsuite/btcwallet/walletdb v1.3.3 // indirect + github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200 // indirect + github.com/muun/libwallet v0.7.0 ) replace github.com/lightninglabs/neutrino => github.com/muun/neutrino v0.0.0-20190914162326-7082af0fa257 diff --git a/go.sum b/go.sum index 34227a8..baf2afe 100644 --- a/go.sum +++ b/go.sum @@ -20,7 +20,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= -github.com/btcsuite/btcd v0.20.0-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.20.1-beta.0.20200513120220-b470eee47728/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= @@ -35,9 +34,6 @@ github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2ut github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/btcutil/psbt v1.0.2 h1:gCVY3KxdoEVU7Q6TjusPO+GANIwVgr9yTLqM+a6CZr8= github.com/btcsuite/btcutil/psbt v1.0.2/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ= -github.com/btcsuite/btcwallet v0.10.0 h1:fFZncfYJ7VByePTGttzJc3qfCyDzU95ucZYk0M912lU= -github.com/btcsuite/btcwallet v0.10.0/go.mod h1:4TqBEuceheGNdeLNrelliLHJzmXauMM2vtWfuy1pFiM= -github.com/btcsuite/btcwallet v0.10.1-0.20191109031858-c49e7ef3ecf1/go.mod h1:4TqBEuceheGNdeLNrelliLHJzmXauMM2vtWfuy1pFiM= github.com/btcsuite/btcwallet v0.11.1-0.20200612012534-48addcd5591a h1:AZ1Mf0gd9mgJqrTTIFUc17ep9EKUbQusVAIzJ6X+x3Q= github.com/btcsuite/btcwallet v0.11.1-0.20200612012534-48addcd5591a/go.mod h1:9+AH3V5mcTtNXTKe+fe63fDLKGOwQbZqmvOVUef+JFE= github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 h1:KGHMW5sd7yDdDMkCZ/JpP0KltolFsQcB973brBnfj4c= @@ -47,8 +43,6 @@ github.com/btcsuite/btcwallet/wallet/txrules v1.0.0/go.mod h1:UwQE78yCerZ313EXZw github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0 h1:6DxkcoMnCPY4E9cUDPB5tbuuf40SmmMkSQkoE8vCT+s= github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= github.com/btcsuite/btcwallet/walletdb v1.0.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk= -github.com/btcsuite/btcwallet/walletdb v1.1.0 h1:JHAL7wZ8pX4SULabeAv/wPO9sseRWMGzE80lfVmRw6Y= -github.com/btcsuite/btcwallet/walletdb v1.1.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk= github.com/btcsuite/btcwallet/walletdb v1.3.1/go.mod h1:9cwc1Yyg4uvd4ZdfdoMnALji+V9gfWSMfxEdLdR5Vwc= github.com/btcsuite/btcwallet/walletdb v1.3.2/go.mod h1:GZCMPNpUu5KE3ASoVd+k06p/1OW8OwNGCCaNWRto2cQ= github.com/btcsuite/btcwallet/walletdb v1.3.3 h1:u6e7vRIKBF++cJy+hOHaMGg+88ZTwvpaY27AFvtB668= @@ -57,7 +51,6 @@ github.com/btcsuite/btcwallet/wtxmgr v1.0.0 h1:aIHgViEmZmZfe0tQQqF1xyd2qBqFWxX5v github.com/btcsuite/btcwallet/wtxmgr v1.0.0/go.mod h1:vc4gBprll6BP0UJ+AIGDaySoc7MdAmZf8kelfNb8CFY= github.com/btcsuite/btcwallet/wtxmgr v1.2.0 h1:ZUYPsSv8GjF9KK7lboB2OVHF0uYEcHxgrCfFWqPd9NA= github.com/btcsuite/btcwallet/wtxmgr v1.2.0/go.mod h1:h8hkcKUE3X7lMPzTUoGnNiw5g7VhGrKEW3KpR2r0VnY= -github.com/btcsuite/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:QcFA8DZHtuIAdYKCq/BzELOaznRsCvwf4zTPmaYwaig= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc= @@ -83,12 +76,15 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/decred/dcrd/lru v1.0.0 h1:Kbsb1SFDsIlaupWPwsPp+dkxiBY1frcS07PCPgotKz8= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= @@ -99,10 +95,12 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= @@ -124,12 +122,18 @@ github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzr github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v0.0.0-20170724004829-f2862b476edc/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.8.6/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hhrutter/lzw v0.0.0-20190827003112-58b82c5a41cc/go.mod h1:yJBvOcu1wLQ9q9XZmfiPfur+3dQJuIhYQsMGLYcItZk= +github.com/hhrutter/lzw v0.0.0-20190829144645-6f07a24e8650 h1:1yY/RQWNSBjJe2GDCIYoLmpWVidrooriUr4QS/zaATQ= +github.com/hhrutter/lzw v0.0.0-20190829144645-6f07a24e8650/go.mod h1:yJBvOcu1wLQ9q9XZmfiPfur+3dQJuIhYQsMGLYcItZk= +github.com/hhrutter/tiff v0.0.0-20190829141212-736cae8d0bc7 h1:o1wMw7uTNyA58IlEdDpxIrtFHTgnvYzA8sCQz8luv94= +github.com/hhrutter/tiff v0.0.0-20190829141212-736cae8d0bc7/go.mod h1:WkUxfS2JUu3qPo6tRld7ISb8HiC0gVSU91kooBMDVok= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= @@ -144,7 +148,9 @@ github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLl github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v0.0.0-20181116074157-8ec929ed50c3/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc= +github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= @@ -162,21 +168,19 @@ github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec h1:n1NeQ3SgUHyISrjFF github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lightninglabs/gozmq v0.0.0-20190710231225-cea2a031735d h1:tt8hwvxl6fksSfchjBGaWu+pnWJQfG1OWiCM20qOSAE= -github.com/lightninglabs/gozmq v0.0.0-20190710231225-cea2a031735d/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d/go.mod h1:KDb67YMzoh4eudnzClmvs2FbiLG9vxISmLApUkCa4uI= -github.com/lightningnetwork/lightning-onion v0.0.0-20190909101754-850081b08b6a/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4= github.com/lightningnetwork/lightning-onion v1.0.1 h1:qChGgS5+aPxFeR6JiUsGvanei1bn6WJpYbvosw/1604= github.com/lightningnetwork/lightning-onion v1.0.1/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4= -github.com/lightningnetwork/lnd v0.8.0-beta h1:HmmhSRTq48qobqQF8YLqNa8eKU8dDBNbWWpr2VzycJM= -github.com/lightningnetwork/lnd v0.8.0-beta/go.mod h1:nq06y2BDv7vwWeMmwgB7P3pT7/Uj7sGf5FzHISVD6t4= github.com/lightningnetwork/lnd v0.10.4-beta h1:Af2zOCPePeaU8Tkl8IqtTjr4BP3zYfi+hAtQYcCMM58= github.com/lightningnetwork/lnd v0.10.4-beta/go.mod h1:4d02pduRVtZwgTJ+EimKJTsEAY0jDwi0SPE9h5aRneM= github.com/lightningnetwork/lnd/cert v1.0.2/go.mod h1:fmtemlSMf5t4hsQmcprSoOykypAPp+9c+0d0iqTScMo= @@ -201,21 +205,25 @@ github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8/go.mod h1:W1PPwlIAgtquWB github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg= github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/muun/libwallet v0.5.0 h1:3YcUuQsnViXdrXntBwV3sLH2RKHC5uNODhuawp+2dg8= -github.com/muun/libwallet v0.5.0/go.mod h1:EdLg8d1sGJ4q4VUKRJyfNDBnbWc+rs5b8pHHu6KF5LY= +github.com/muun/libwallet v0.7.0 h1:FfPt+L7WN02qIgG9oJgVc9wBs7fw9w6PgHOsEI56o60= +github.com/muun/libwallet v0.7.0/go.mod h1:CB5ooFhTjbewO1YlP74Hnlf1PHWZhTU58g7LU3c2+fw= github.com/muun/neutrino v0.0.0-20190914162326-7082af0fa257 h1:NW17wq2gZlEFeW3/Zx3wSmqlD0wKGf7YvhpP+CNCsbE= github.com/muun/neutrino v0.0.0-20190914162326-7082af0fa257/go.mod h1:awTrhbCWjWNH4yVwZ4IE7nZbvpQ27e7OyD+jao7wRxA= +github.com/muun/recovery v0.3.0 h1:YyCXcuGx+SluVa0bHsyaXiowB67rdpJ6AudKv8QGvEE= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pdfcpu/pdfcpu v0.3.8 h1:wdKii186dzmr/aP/fkJl2s9yT3TZcwc1VqgfabNymGI= +github.com/pdfcpu/pdfcpu v0.3.8/go.mod h1:EfJ1EIo3n5+YlGF53DGe1yF1wQLiqK1eqGDN5LuKALs= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= @@ -236,6 +244,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02/go.mod h1:tHlrkM198S068ZqfrO6S8HsoJq2bF3ETfTL+kt4tInY= @@ -251,8 +260,6 @@ golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -262,6 +269,9 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190823064033-3a9bac650e44/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM= +golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -294,6 +304,7 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -311,6 +322,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -324,6 +336,7 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -349,8 +362,10 @@ google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gormigrate.v1 v1.6.0 h1:XpYM6RHQPmzwY7Uyu+t+xxMXc86JYFJn4nEc9HzQjsI= gopkg.in/gormigrate.v1 v1.6.0/go.mod h1:Lf00lQrHqfSYWiTtPcyQabsDdM6ejZaMgV0OU6JMSlw= @@ -358,10 +373,14 @@ gopkg.in/macaroon-bakery.v2 v2.0.1/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETf gopkg.in/macaroon.v2 v2.0.0/go.mod h1:+I6LnTMkm/uV5ew/0nsulNjL16SK4+C8yDmRUzHR17I= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/keys_generator.go b/keys_generator.go index d03461d..ca797f7 100644 --- a/keys_generator.go +++ b/keys_generator.go @@ -1,31 +1,44 @@ package main import ( + "encoding/hex" log "log" "github.com/btcsuite/btcutil/base58" "github.com/muun/libwallet" ) -func buildExtendedKey(rawKey, recoveryCode string) *libwallet.DecryptedPrivateKey { - salt := extractSalt(rawKey) +var defaultNetwork = libwallet.Mainnet() + +func buildExtendedKeys(rawKey1, rawKey2, recoveryCode string) ( + *libwallet.DecryptedPrivateKey, + *libwallet.DecryptedPrivateKey) { + + // Always take the salt from the second key (the same salt was used, but our older key format + // is missing the salt on the first key): + salt := extractSalt(rawKey2) decryptionKey, err := libwallet.RecoveryCodeToKey(recoveryCode, salt) if err != nil { log.Fatalf("failed to process recovery code: %v", err) } - walletKey, err := decryptionKey.DecryptKey(rawKey, libwallet.Mainnet()) + key1, err := decryptionKey.DecryptKey(rawKey1, defaultNetwork) if err != nil { - log.Fatalf("failed to decrypt key: %v", err) + log.Fatalf("failed to decrypt first key: %v", err) } - return walletKey + key2, err := decryptionKey.DecryptKey(rawKey2, defaultNetwork) + if err != nil { + log.Fatalf("failed to decrypt second key: %v", err) + } + + return key1, key2 } func extractSalt(rawKey string) string { bytes := base58.Decode(rawKey) saltBytes := bytes[len(bytes)-8:] - return string(saltBytes) + return hex.EncodeToString(saltBytes) } diff --git a/main.go b/main.go index 4df334e..4c25335 100644 --- a/main.go +++ b/main.go @@ -8,39 +8,36 @@ import ( "strings" "github.com/btcsuite/btcutil" + "github.com/muun/libwallet" ) func main() { - chainService, close, _ := startChainService() - defer close() - printWelcomeMessage() recoveryCode := readRecoveryCode() - userRawKey := readKey("first encrypted private key", 147) - userKey := buildExtendedKey(userRawKey, recoveryCode) - userKey.Key.Path = "m/1'/1'" + userRawKey := readKey("first encrypted private key") + muunRawKey := readKey("second encrypted private key") - muunRawKey := readKey("second encrypted private key", 147) - muunKey := buildExtendedKey(muunRawKey, recoveryCode) + userKey, muunKey := buildExtendedKeys(userRawKey, muunRawKey, recoveryCode) + userKey.Key.Path = "m/1'/1'" sweepAddress := readSweepAddress() fmt.Println("") - fmt.Println("Preparing to scan the blockchain from your wallet creation block") - fmt.Println("Note that only confirmed transactions can be detected") - fmt.Println("\nThis may take a while") + fmt.Println("\nStarting scan of all your addresses. This may take a while") sweeper := Sweeper{ - ChainService: chainService, UserKey: userKey.Key, MuunKey: muunKey.Key, Birthday: muunKey.Birthday, SweepAddress: sweepAddress, } - utxos := sweeper.GetUTXOs() + utxos, err := sweeper.GetUTXOs() + if err != nil { + exitWithError(err) + } fmt.Println("") @@ -131,21 +128,29 @@ func readRecoveryCode() string { return finalRC } -func readKey(keyType string, characters int) string { +func readKey(keyType string) string { fmt.Println("") fmt.Printf("Enter your %v", keyType) fmt.Println() fmt.Println("(it looks like this: '9xzpc7y6sNtRvh8Fh...')") fmt.Print("> ") - userInput := scanMultiline(characters) + // NOTE: + // Users will most likely copy and paste their keys from the Emergency Kit PDF. In this case, + // input will come suddenly in multiple lines, so a simple scan & retry (let's say 3 lines + // were pasted) will attempt to parse a key and fail 2 times in a row, with leftover characters + // until the user presses enter to fail for a 3rd time. - if len(userInput) != characters { - fmt.Printf("Your %v must have %v characters", keyType, characters) - fmt.Println("") - fmt.Println("Please, try again") + // Given the line lengths actually found in our Emergency Kits, we have a simple solution for now: + // scan a minimum length of characters. Pasing from current versions of the Emergency Kit will + // only go past a minimum length when the key being entered is complete, in all cases. + userInput := scanMultiline(libwallet.EncodedKeyLengthLegacy) - return readKey(keyType, characters) + if len(userInput) < libwallet.EncodedKeyLengthLegacy { + // This is obviously invalid. Other problems will be detected later on, during the actual + // decoding and decryption stage. + fmt.Println("The key you entered doesn't look valid\nPlease, try again") + return readKey(keyType) } return userInput @@ -239,3 +244,8 @@ func scanMultiline(minChars int) string { return result.String() } + +func exitWithError(reason error) { + fmt.Println("\nError while scanning. Can't continue. Please, try again later.") + os.Exit(1) +} diff --git a/scanner/scanner.go b/scanner/scanner.go new file mode 100644 index 0000000..648af19 --- /dev/null +++ b/scanner/scanner.go @@ -0,0 +1,193 @@ +package scanner + +import ( + "sync" + "time" + + "github.com/muun/libwallet" + "github.com/muun/recovery/electrum" + "github.com/muun/recovery/utils" +) + +const electrumPoolSize = 3 +const taskTimeout = 2 * time.Minute +const batchSize = 100 + +// Scanner finds unspent outputs and their transactions when given a map of addresses. +// +// It implements multi-server support, batching feature detection and use, concurrency control, +// timeouts and cancelations, and provides a channel-based interface. +// +// Servers are provided by a ServerProvider instance, and rotated when unreachable or faulty. We +// trust ServerProvider to prioritize good targets. +// +// Batching is leveraged when supported by a particular server, falling back to sequential requests +// for single addresses (which is much slower, but can get us out of trouble when better servers are +// not available). +// +// Timeouts and cancellations are an internal affair, not configurable by callers. See taskTimeout +// declared above. +// +// Concurrency control works by using an electrum.Pool, limiting access to clients, and not an +// internal worker pool. This is the Go way (limiting access to resources rather than having a fixed +// number of parallel goroutines), and (more to the point) semantically correct. We don't care +// about the number of concurrent workers, what we want to avoid is too many connections to +// Electrum servers. +type Scanner struct { + pool *electrum.Pool + servers *ServerProvider + log *utils.Logger +} + +// Utxo references a transaction output, plus the associated MuunAddress and script. +type Utxo struct { + TxID string + OutputIndex int + Amount int + Address libwallet.MuunAddress + Script []byte +} + +// scanContext contains the synchronization objects for a single Scanner round, to manage Tasks. +type scanContext struct { + addresses chan libwallet.MuunAddress + results chan Utxo + errors chan error + done chan struct{} + wg *sync.WaitGroup +} + +// NewScanner creates an initialized Scanner. +func NewScanner() *Scanner { + return &Scanner{ + pool: electrum.NewPool(electrumPoolSize), + servers: NewServerProvider(), + log: utils.NewLogger("Scanner"), + } +} + +// Scan an address space and return all relevant transactions for a sweep. +func (s *Scanner) Scan(addresses chan libwallet.MuunAddress) ([]Utxo, error) { + var results []Utxo + var waitGroup sync.WaitGroup + + // Create the Context that goroutines will share: + ctx := &scanContext{ + addresses: addresses, + results: make(chan Utxo), + errors: make(chan error), + done: make(chan struct{}), + wg: &waitGroup, + } + + // Start the scan in background: + go s.startScan(ctx) + + // Collect all results until the done signal, or abort on the first error: + for { + select { + case err := <-ctx.errors: + close(ctx.done) // send the done signal ourselves + return nil, err + + case result := <-ctx.results: + results = append(results, result) + + case <-ctx.done: + return results, nil + } + } +} + +func (s *Scanner) startScan(ctx *scanContext) { + s.log.Printf("Scan started") + + batches := streamBatches(ctx.addresses) + + var client *electrum.Client + + for batch := range batches { + // Stop the loop until a client becomes available, or the scan is canceled: + select { + case <-ctx.done: + return + + case client = <-s.pool.Acquire(): + } + + // Start scanning this address in background: + ctx.wg.Add(1) + + go func(batch []libwallet.MuunAddress) { + defer s.pool.Release(client) + defer ctx.wg.Done() + + s.scanBatch(ctx, client, batch) + }(batch) + } + + // Wait for all tasks that are still executing to complete: + ctx.wg.Wait() + s.log.Printf("Scan complete") + + // Signal to the Scanner that this Context has no more pending work: + close(ctx.done) +} + +func (s *Scanner) scanBatch(ctx *scanContext, client *electrum.Client, batch []libwallet.MuunAddress) { + // NOTE: + // We begin by building the task, passing our selected Client. Since we're choosing the instance, + // it's our job to control acquisition and release of Clients to prevent sharing (remember, + // clients are single-user). The task won't enforce this safety measure (it can't), it's fully + // up to us. + task := &scanTask{ + servers: s.servers, + client: client, + addresses: batch, + timeout: taskTimeout, + exit: ctx.done, + } + + // Do the thing: + addressResults, err := task.Execute() + + if err != nil { + ctx.errors <- s.log.Errorf("Scan failed: %w", err) + return + } + + // Send back all results: + for _, result := range addressResults { + ctx.results <- result + } +} + +func streamBatches(addresses chan libwallet.MuunAddress) chan []libwallet.MuunAddress { + batches := make(chan []libwallet.MuunAddress) + + go func() { + var nextBatch []libwallet.MuunAddress + + for address := range addresses { + // Add items to the batch until we reach the limit: + nextBatch = append(nextBatch, address) + + if len(nextBatch) < batchSize { + continue + } + + // Send back the batch and start over: + batches <- nextBatch + nextBatch = []libwallet.MuunAddress{} + } + + // Send back an incomplete batch with any remaining addresses: + if len(nextBatch) > 0 { + batches <- nextBatch + } + + close(batches) + }() + + return batches +} diff --git a/scanner/servers.go b/scanner/servers.go new file mode 100644 index 0000000..37fe4a0 --- /dev/null +++ b/scanner/servers.go @@ -0,0 +1,97 @@ +package scanner + +import "sync/atomic" + +// ServerProvider manages a rotating server list, from which callers can pull server addresses. +type ServerProvider struct { + nextIndex int32 +} + +// NewServerProvider returns an initialized ServerProvider. +func NewServerProvider() *ServerProvider { + return &ServerProvider{-1} +} + +// NextServer returns an address from the rotating list. It's thread-safe. +func (p *ServerProvider) NextServer() string { + index := int(atomic.AddInt32(&p.nextIndex, 1)) + return PublicElectrumServers[index%len(PublicElectrumServers)] +} + +// PublicElectrumServers list. +// +// This list was taken from the `electrum` repository, keeping TLS servers and excluding onion URIs. +// It was then sorted into sections using the `cmd/survey` program, to prioritize the more reliable +// servers with batch support. +// +// See https://github.com/spesmilo/electrum/blob/master/electrum/servers.json +// See `cmd/survey/main.go` +// +var PublicElectrumServers = []string{ + // With batch support: + "electrum.hsmiths.com:50002", + "E-X.not.fyi:50002", + "VPS.hsmiths.com:50002", + "btc.cihar.com:50002", + "e.keff.org:50002", + "electrum.qtornado.com:50002", + "electrum.emzy.de:50002", + "tardis.bauerj.eu:50002", + "electrum.hodlister.co:50002", + "electrum3.hodlister.co:50002", + "electrum5.hodlister.co:50002", + "fortress.qtornado.com:443", + "electrumx.erbium.eu:50002", + "bitcoin.lukechilds.co:50002", + "electrum.bitkoins.nl:50512", + + // Without batch support: + "electrum.aantonop.com:50002", + "electrum.blockstream.info:50002", + "blockstream.info:700", + + // Unclassified: + "81-7-10-251.blue.kundencontroller.de:50002", + "b.ooze.cc:50002", + "bitcoin.corgi.party:50002", + "bitcoins.sk:50002", + "btc.xskyx.net:50002", + "electrum.jochen-hoenicke.de:50005", + "dragon085.startdedicated.de:50002", + "e-1.claudioboxx.com:50002", + "electrum-server.ninja:50002", + "electrum-unlimited.criptolayer.net:50002", + "electrum.eff.ro:50002", + "electrum.festivaldelhumor.org:50002", + "electrum.leblancnet.us:50002", + "electrum.mindspot.org:50002", + "electrum.taborsky.cz:50002", + "electrum.villocq.com:50002", + "electrum2.eff.ro:50002", + "electrum2.villocq.com:50002", + "electrumx.bot.nu:50002", + "electrumx.ddns.net:50002", + "electrumx.ftp.sh:50002", + "electrumx.soon.it:50002", + "elx01.knas.systems:50002", + "fedaykin.goip.de:50002", + "fn.48.org:50002", + "ndnd.selfhost.eu:50002", + "orannis.com:50002", + "rbx.curalle.ovh:50002", + "technetium.network:50002", + "tomscryptos.com:50002", + "ulrichard.ch:50002", + "vmd27610.contaboserver.net:50002", + "vmd30612.contaboserver.net:50002", + "xray587.startdedicated.de:50002", + "yuio.top:50002", + "bitcoin.dragon.zone:50004", + "ecdsa.net:110", + "btc.usebsv.com:50006", + "e2.keff.org:50002", + "electrumx.electricnewyear.net:50002", + "green-gold.westeurope.cloudapp.azure.com:56002", + "electrumx-core.1209k.com:50002", + "bitcoin.aranguren.org:50002", +} diff --git a/scanner/task.go b/scanner/task.go new file mode 100644 index 0000000..a63a7cb --- /dev/null +++ b/scanner/task.go @@ -0,0 +1,180 @@ +package scanner + +import ( + "fmt" + "time" + + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcutil" + "github.com/muun/libwallet" + "github.com/muun/recovery/electrum" +) + +// scanTask encapsulates a parallelizable Scanner unit of work. +type scanTask struct { + servers *ServerProvider + client *electrum.Client + addresses []libwallet.MuunAddress + timeout time.Duration + exit chan struct{} +} + +// Execute obtains the Utxo set for the Task address, implementing a retry strategy. +func (t *scanTask) Execute() ([]Utxo, error) { + results := make(chan []Utxo) + errors := make(chan error) + timeout := time.After(t.timeout) + + // Keep the last error around, in case we reach the timeout and want to know the reason: + var lastError error + + for { + // Attempt to run the task: + go t.tryExecuteAsync(results, errors) + + // Wait until a result is sent, the timeout is reached or the task canceled, capturing errors + // errors along the way: + select { + case <-t.exit: + return []Utxo{}, nil // stop retrying when we get the done signal + + case result := <-results: + return result, nil + + case err := <-errors: + lastError = err + + case <-timeout: + return nil, fmt.Errorf("Task timed out. Last error: %w", lastError) + } + } +} + +func (t *scanTask) tryExecuteAsync(results chan []Utxo, errors chan error) { + // Errors will almost certainly arise from Electrum server failures, which are extremely + // common. Unreachable IPs, dropped connections, sudden EOFs, etc. We'll run this task, assuming + // the servers are at fault when something fails, disconnecting and cycling them as we retry. + result, err := t.tryExecute() + + if err != nil { + t.client.Disconnect() + errors <- err + return + } + + results <- result +} + +func (t *scanTask) tryExecute() ([]Utxo, error) { + // If our client is not connected, make an attempt to connect to a server: + if !t.client.IsConnected() { + err := t.client.Connect(t.servers.NextServer()) + + if err != nil { + return nil, err + } + } + + // Prepare the output scripts for all given addresses: + outputScripts, err := getOutputScripts(t.addresses) + if err != nil { + return nil, err + } + + // Prepare the index hashes that Electrum requires to list outputs: + indexHashes, err := getIndexHashes(outputScripts) + if err != nil { + return nil, err + } + + // Call Electrum to get the unspent output list, grouped by index for each address: + var unspentRefGroups [][]electrum.UnspentRef + + if t.client.SupportsBatching() { + unspentRefGroups, err = t.listUnspentWithBatching(indexHashes) + } else { + unspentRefGroups, err = t.listUnspentWithoutBatching(indexHashes) + } + + if err != nil { + return nil, err + } + + // Compile the results into a list of `Utxos`: + var utxos []Utxo + + for i, unspentRefGroup := range unspentRefGroups { + for _, unspentRef := range unspentRefGroup { + newUtxo := Utxo{ + TxID: unspentRef.TxHash, + OutputIndex: unspentRef.TxPos, + Amount: unspentRef.Value, + Script: outputScripts[i], + Address: t.addresses[i], + } + + utxos = append(utxos, newUtxo) + } + } + + return utxos, nil +} + +func (t *scanTask) listUnspentWithBatching(indexHashes []string) ([][]electrum.UnspentRef, error) { + unspentRefGroups, err := t.client.ListUnspentBatch(indexHashes) + if err != nil { + return nil, fmt.Errorf("Listing with batching failed: %w", err) + } + + return unspentRefGroups, nil +} + +func (t *scanTask) listUnspentWithoutBatching(indexHashes []string) ([][]electrum.UnspentRef, error) { + var unspentRefGroups [][]electrum.UnspentRef + + for _, indexHash := range indexHashes { + newGroup, err := t.client.ListUnspent(indexHash) + if err != nil { + return nil, fmt.Errorf("Listing without batching failed: %w", err) + } + + unspentRefGroups = append(unspentRefGroups, newGroup) + } + + return unspentRefGroups, nil +} + +// getIndexHashes calculates all the Electrum index hashes for a list of output scripts. +func getIndexHashes(outputScripts [][]byte) ([]string, error) { + indexHashes := make([]string, len(outputScripts)) + + for i, outputScript := range outputScripts { + indexHashes[i] = electrum.GetIndexHash(outputScript) + } + + return indexHashes, nil +} + +// getOutputScripts creates all the scripts that send to an list of Bitcoin address. +func getOutputScripts(addresses []libwallet.MuunAddress) ([][]byte, error) { + outputScripts := make([][]byte, len(addresses)) + + for i, address := range addresses { + rawAddress := address.Address() + + decodedAddress, err := btcutil.DecodeAddress(rawAddress, &chaincfg.MainNetParams) + if err != nil { + return nil, fmt.Errorf("Failed to decode address %s: %w", rawAddress, err) + } + + outputScript, err := txscript.PayToAddrScript(decodedAddress) + if err != nil { + return nil, fmt.Errorf("Failed to craft script for %s: %w", rawAddress, err) + } + + outputScripts[i] = outputScript + } + + return outputScripts, nil +} diff --git a/sweeper.go b/sweeper.go index 1848f15..199515f 100644 --- a/sweeper.go +++ b/sweeper.go @@ -1,30 +1,78 @@ package main import ( + "bytes" + "encoding/hex" + "fmt" + + "github.com/muun/recovery/electrum" + "github.com/muun/recovery/scanner" + + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" - "github.com/lightninglabs/neutrino" "github.com/muun/libwallet" ) +var ( + chainParams = chaincfg.MainNetParams +) + type Sweeper struct { - ChainService *neutrino.ChainService UserKey *libwallet.HDPrivateKey MuunKey *libwallet.HDPrivateKey Birthday int SweepAddress btcutil.Address } -func (s *Sweeper) GetUTXOs() []*RelevantTx { - g := NewAddressGenerator(s.UserKey, s.MuunKey) - g.Generate() +// RelevantTx contains a PKScipt, an Address an a boolean to check if its spent or not +type RelevantTx struct { + PkScript []byte + Address string + Spent bool + Satoshis int64 + SigningDetails signingDetails + Outpoint wire.OutPoint +} - birthday := s.Birthday - if birthday == 0xFFFF { - birthday = 0 +func (tx *RelevantTx) String() string { + return fmt.Sprintf("outpoint %v:%v for %v sats on path %v", + tx.Outpoint.Hash, tx.Outpoint.Index, tx.Satoshis, tx.SigningDetails.Address.DerivationPath()) +} + +func (s *Sweeper) GetUTXOs() ([]*RelevantTx, error) { + addresses := s.generateAddresses() + + results, err := scanner.NewScanner().Scan(addresses) + if err != nil { + return nil, fmt.Errorf("error while scanning addresses: %w", err) } - return startRescan(s.ChainService, g.Addresses(), birthday) + txs, err := buildRelevantTxs(results) + if err != nil { + return nil, fmt.Errorf("error while crafting transaction: %w", err) + } + + return txs, nil +} + +func (s *Sweeper) generateAddresses() chan libwallet.MuunAddress { + ch := make(chan libwallet.MuunAddress) + + go func() { + g := NewAddressGenerator(s.UserKey, s.MuunKey) + g.Generate() + + for _, details := range g.Addresses() { + ch <- details.Address + } + + close(ch) + }() + + return ch } func (s *Sweeper) GetSweepTxAmountAndWeightInBytes(utxos []*RelevantTx) (outputAmount int64, weightInBytes int64, err error) { @@ -50,5 +98,59 @@ func (s *Sweeper) BuildSweepTx(utxos []*RelevantTx, fee int64) (*wire.MsgTx, err } func (s *Sweeper) BroadcastTx(tx *wire.MsgTx) error { - return s.ChainService.SendTransaction(tx) + // Connect to an Electurm server using a fresh client and provider pair: + sp := scanner.NewServerProvider() // TODO create servers module, for provider and pool + client := electrum.NewClient() + + for !client.IsConnected() { + client.Connect(sp.NextServer()) + } + + // Encode the transaction for broadcast: + txBytes := new(bytes.Buffer) + + err := tx.BtcEncode(txBytes, wire.ProtocolVersion, wire.WitnessEncoding) + if err != nil { + return fmt.Errorf("error while encoding tx: %w", err) + } + + txHex := hex.EncodeToString(txBytes.Bytes()) + + // Do the thing! + _, err = client.Broadcast(txHex) + if err != nil { + return fmt.Errorf("error while broadcasting: %w", err) + } + + return nil +} + +// buildRelevantTxs prepares the output from Scanner for crafting. +func buildRelevantTxs(utxos []scanner.Utxo) ([]*RelevantTx, error) { + var relevantTxs []*RelevantTx + + for _, utxo := range utxos { + address := utxo.Address.Address() + + chainHash, err := chainhash.NewHashFromStr(utxo.TxID) + if err != nil { + return nil, err + } + + relevantTx := &RelevantTx{ + PkScript: utxo.Script, + Address: address, + Spent: false, + Satoshis: int64(utxo.Amount), + SigningDetails: signingDetails{utxo.Address}, + Outpoint: wire.OutPoint{ + Hash: *chainHash, + Index: uint32(utxo.OutputIndex), + }, + } + + relevantTxs = append(relevantTxs, relevantTx) + } + + return relevantTxs, nil } diff --git a/utils/logger.go b/utils/logger.go new file mode 100644 index 0000000..72e058c --- /dev/null +++ b/utils/logger.go @@ -0,0 +1,53 @@ +package utils + +import ( + "fmt" + "os" + "strings" +) + +// DebugMode is true when the `DEBUG` environment variable is set to "true". +var DebugMode bool = os.Getenv("DEBUG") == "true" + +// Logger provides logging methods that only print when `DebugMode` is true. +// This allows callers to log detailed information without displaying it to users during normal +// execution. +type Logger struct { + tag string +} + +// NewLogger returns an initialized Logger instance. +func NewLogger(tag string) *Logger { + return &Logger{tag} +} + +// SetTag updates the tag of this Logger. +func (l *Logger) SetTag(newTag string) { + l.tag = newTag +} + +// Printf works like fmt.Printf, but only prints when `DebugMode` is true. +func (l *Logger) Printf(format string, v ...interface{}) { + if !DebugMode { + return + } + + message := strings.TrimSpace(fmt.Sprintf(format, v...)) + + fmt.Printf("%s %s\n", l.getPrefix(), message) +} + +// Errorf works like fmt.Errorf, but prints the error to the console if `DebugMode` is true. +func (l *Logger) Errorf(format string, v ...interface{}) error { + err := fmt.Errorf(format, v...) + + if DebugMode { + fmt.Printf("%s %v\n", l.getPrefix(), err) + } + + return err +} + +func (l *Logger) getPrefix() string { + return fmt.Sprintf("[%s]", l.tag) +} diff --git a/vendor/github.com/hhrutter/lzw/.gitignore b/vendor/github.com/hhrutter/lzw/.gitignore new file mode 100644 index 0000000..31651d6 --- /dev/null +++ b/vendor/github.com/hhrutter/lzw/.gitignore @@ -0,0 +1,6 @@ +# Mac +**/.DS_Store +**/._.DS_Store + +# VSCode +.vscode/* \ No newline at end of file diff --git a/vendor/github.com/hhrutter/lzw/LICENSE b/vendor/github.com/hhrutter/lzw/LICENSE new file mode 100644 index 0000000..6a66aea --- /dev/null +++ b/vendor/github.com/hhrutter/lzw/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/hhrutter/lzw/README.md b/vendor/github.com/hhrutter/lzw/README.md new file mode 100644 index 0000000..bdee415 --- /dev/null +++ b/vendor/github.com/hhrutter/lzw/README.md @@ -0,0 +1,37 @@ +# Note + +* This is a consolidated version of [compress/lzw](https://github.com/golang/go/tree/master/src/compress/lzw) that supports GIF, TIFF and PDF. +* Please refer to this [golang proposal](https://github.com/golang/go/issues/25409) for details. +* [github.com/hhrutter/tiff](https://github.com/hhrutter/tiff) uses this package to extend [x/image/tiff](https://github.com/golang/image/tree/master/tiff). +* [pdfcpu](https://github.com/pdfcpu/pdfcpu) uses this package for processing PDFs with embedded TIFF images. + + +## Background + +* PDF's LZWDecode filter comes with the optional parameter `EarlyChange`. +* The type of this parameter is `int` and the defined values are 0 and 1. +* The default value is 1. + +This parameter implies two variants of lzw. (See the [PDF spec](https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf)). + +[compress/lzw](https://github.com/golang/go/tree/master/src/compress/lzw): + +* the algorithm implied by EarlyChange value 1 +* provides both Reader and Writer. + +[x/image/tiff/lzw](https://github.com/golang/image/tree/master/tiff/lzw): + +* the algorithm implied by EarlyChange value 0 +* provides a Reader, lacks a Writer + +In addition PDF expects a leading `clear_table` marker right at the beginning +which is not something [compress/lzw](https://github.com/golang/go/tree/master/src/compress/lzw) takes into account. + +There are numerous PDF Writers out there and for arbitrary PDF files using the LZWDecode filter the following can be observed: + +* Some PDF writers do not write the EOD (end of data) marker. +* Some PDF writers do not write the final bits after the EOD marker. + +## Goal + +An extended version of [compress/lzw](https://github.com/golang/go/tree/master/src/compress/lzw) with reliable support for GIF, TIFF and PDF. diff --git a/vendor/github.com/hhrutter/lzw/go.mod b/vendor/github.com/hhrutter/lzw/go.mod new file mode 100644 index 0000000..eb3ac3c --- /dev/null +++ b/vendor/github.com/hhrutter/lzw/go.mod @@ -0,0 +1,3 @@ +module github.com/hhrutter/lzw + +go 1.12 diff --git a/vendor/github.com/hhrutter/lzw/reader.go b/vendor/github.com/hhrutter/lzw/reader.go new file mode 100644 index 0000000..7230a1d --- /dev/null +++ b/vendor/github.com/hhrutter/lzw/reader.go @@ -0,0 +1,238 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package lzw is an enhanced version of compress/lzw. +// +// It implements Adobe's PDF lzw compression as defined for the LZWDecode filter +// and is also compatible with the TIFF file format. +// +// See the golang proposal: https://github.com/golang/go/issues/25409. +// +// More information: https://github.com/pdfcpu/pdfcpu/tree/master/lzw +package lzw + +import ( + "bufio" + "errors" + "io" +) + +const ( + maxWidth = 12 + decoderInvalidCode = 0xffff + flushBuffer = 1 << maxWidth +) + +// decoder is the state from which the readXxx method converts a byte +// stream into a code stream. +type decoder struct { + r io.ByteReader + bits uint32 + nBits uint + width uint + read func(*decoder) (uint16, error) // readMSB always for PDF and TIFF + litWidth uint // width in bits of literal codes + err error + + // The first 1<= 1<> (32 - d.width)) + d.bits <<= d.width + d.nBits -= d.width + return code, nil +} + +func (d *decoder) Read(b []byte) (int, error) { + for { + if len(d.toRead) > 0 { + n := copy(b, d.toRead) + d.toRead = d.toRead[n:] + return n, nil + } + if d.err != nil { + return 0, d.err + } + d.decode() + } +} + +func (d *decoder) handleOverflow() { + ui := d.hi + if d.oneOff { + ui++ + } + if ui >= d.overflow { + if d.width == maxWidth { + d.last = decoderInvalidCode + // Undo the d.hi++ a few lines above, so that (1) we maintain + // the invariant that d.hi <= d.overflow, and (2) d.hi does not + // eventually overflow a uint16. + if !d.oneOff { + d.hi-- + } + } else { + d.width++ + d.overflow <<= 1 + } + } +} + +// decode decompresses bytes from r and leaves them in d.toRead. +// read specifies how to decode bytes into codes. +// litWidth is the width in bits of literal codes. +func (d *decoder) decode() { + i := 0 + // Loop over the code stream, converting codes into decompressed bytes. +loop: + for { + code, err := d.read(d) + i++ + if err != nil { + // Some PDF Writers write an EOD some don't. + // Don't insist on EOD marker. + // Don't return an unexpected EOF error. + d.err = err + break + } + switch { + case code < d.clear: + // We have a literal code. + d.output[d.o] = uint8(code) + d.o++ + if d.last != decoderInvalidCode { + // Save what the hi code expands to. + d.suffix[d.hi] = uint8(code) + d.prefix[d.hi] = d.last + } + case code == d.clear: + d.width = 1 + d.litWidth + d.hi = d.eof + d.overflow = 1 << d.width + d.last = decoderInvalidCode + continue + case code == d.eof: + d.err = io.EOF + break loop + case code <= d.hi: + c, i := code, len(d.output)-1 + if code == d.hi && d.last != decoderInvalidCode { + // code == hi is a special case which expands to the last expansion + // followed by the head of the last expansion. To find the head, we walk + // the prefix chain until we find a literal code. + c = d.last + for c >= d.clear { + c = d.prefix[c] + } + d.output[i] = uint8(c) + i-- + c = d.last + } + // Copy the suffix chain into output and then write that to w. + for c >= d.clear { + d.output[i] = d.suffix[c] + i-- + c = d.prefix[c] + } + d.output[i] = uint8(c) + d.o += copy(d.output[d.o:], d.output[i:]) + if d.last != decoderInvalidCode { + // Save what the hi code expands to. + d.suffix[d.hi] = uint8(c) + d.prefix[d.hi] = d.last + } + default: + d.err = errors.New("lzw: invalid code") + break loop + } + d.last, d.hi = code, d.hi+1 + d.handleOverflow() + if d.o >= flushBuffer { + break + } + } + // Flush pending output. + d.toRead = d.output[:d.o] + d.o = 0 +} + +var errClosed = errors.New("lzw: reader/writer is closed") + +func (d *decoder) Close() error { + d.err = errClosed // in case any Reads come along + return nil +} + +// NewReader creates a new io.ReadCloser. +// Reads from the returned io.ReadCloser read and decompress data from r. +// If r does not also implement io.ByteReader, +// the decompressor may read more data than necessary from r. +// It is the caller's responsibility to call Close on the ReadCloser when +// finished reading. +// oneOff makes code length increases occur one code early. It should be true +// for LZWDecode filters with earlyChange=1 which is also the default. +func NewReader(r io.Reader, oneOff bool) io.ReadCloser { + + br, ok := r.(io.ByteReader) + if !ok { + br = bufio.NewReader(r) + } + + lw := uint(8) + clear := uint16(1) << lw + width := 1 + lw + + return &decoder{ + r: br, + read: (*decoder).readMSB, + litWidth: lw, + width: width, + clear: clear, + eof: clear + 1, + hi: clear + 1, + overflow: uint16(1) << width, + last: decoderInvalidCode, + oneOff: oneOff, + } +} diff --git a/vendor/github.com/hhrutter/lzw/writer.go b/vendor/github.com/hhrutter/lzw/writer.go new file mode 100644 index 0000000..dd42b12 --- /dev/null +++ b/vendor/github.com/hhrutter/lzw/writer.go @@ -0,0 +1,283 @@ +// Derived from compress/lzw in order to implement +// Adobe's PDF lzw compression as defined for the LZWDecode filter. +// See https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf +// and https://github.com/golang/go/issues/25409. +// +// It is also compatible with the TIFF file format. +// +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package lzw + +import ( + "bufio" + "errors" + "io" +) + +// A writer is a buffered, flushable writer. +type writer interface { + io.ByteWriter + Flush() error +} + +// An errWriteCloser is an io.WriteCloser that always returns a given error. +type errWriteCloser struct { + err error +} + +func (e *errWriteCloser) Write([]byte) (int, error) { + return 0, e.err +} + +func (e *errWriteCloser) Close() error { + return e.err +} + +const ( + // A code is a 12 bit value, stored as a uint32 when encoding to avoid + // type conversions when shifting bits. + maxCode = 1<<12 - 1 + invalidCode = 1<<32 - 1 + // There are 1<<12 possible codes, which is an upper bound on the number of + // valid hash table entries at any given point in time. tableSize is 4x that. + tableSize = 4 * 1 << 12 + tableMask = tableSize - 1 + // A hash table entry is a uint32. Zero is an invalid entry since the + // lower 12 bits of a valid entry must be a non-literal code. + invalidEntry = 0 +) + +// encoder is LZW compressor. +type encoder struct { + // w is the writer that compressed bytes are written to. + w writer + // write, bits, nBits and width are the state for + // converting a code stream into a byte stream. + write func(*encoder, uint32) error + bits uint32 + nBits uint + width uint + // litWidth is the width in bits of literal codes. + litWidth uint + // hi is the code implied by the next code emission. + // overflow is the code at which hi overflows the code width. + hi, overflow uint32 + // savedCode is the accumulated code at the end of the most recent Write + // call. It is equal to invalidCode if there was no such call. + savedCode uint32 + // err is the first error encountered during writing. Closing the encoder + // will make any future Write calls return errClosed + err error + // table is the hash table from 20-bit keys to 12-bit values. Each table + // entry contains key<<12|val and collisions resolve by linear probing. + // The keys consist of a 12-bit code prefix and an 8-bit byte suffix. + // The values are a 12-bit code. + table [tableSize]uint32 + // oneOff makes code length increases occur one code early. + oneOff bool +} + +// writeLSB writes the code c for "Least Significant Bits first" data. +func (e *encoder) writeLSB(c uint32) error { + e.bits |= c << e.nBits + e.nBits += e.width + for e.nBits >= 8 { + if err := e.w.WriteByte(uint8(e.bits)); err != nil { + return err + } + e.bits >>= 8 + e.nBits -= 8 + } + return nil +} + +// writeMSB writes the code c for "Most Significant Bits first" data. +func (e *encoder) writeMSB(c uint32) error { + e.bits |= c << (32 - e.width - e.nBits) + e.nBits += e.width + for e.nBits >= 8 { + if err := e.w.WriteByte(uint8(e.bits >> 24)); err != nil { + return err + } + e.bits <<= 8 + e.nBits -= 8 + } + return nil +} + +// errOutOfCodes is an internal error that means that the encoder has run out +// of unused codes and a clear code needs to be sent next. +var errOutOfCodes = errors.New("lzw: out of codes") + +// incHi increments e.hi and checks for both overflow and running out of +// unused codes. In the latter case, incHi sends a clear code, resets the +// encoder state and returns errOutOfCodes. +func (e *encoder) incHi() error { + e.hi++ + + // The PDF spec defines for the LZWDecode filter a parameter "EarlyChange". + // This parameter drives the variation of lzw compression to be used. + // The standard compress/lzw does not know about oneOff. + ui := e.hi + if e.oneOff { + ui++ + } + + if ui == e.overflow { + e.width++ + e.overflow <<= 1 + } + + if ui == maxCode { + clear := uint32(1) << e.litWidth + if err := e.write(e, clear); err != nil { + return err + } + e.width = e.litWidth + 1 + e.hi = clear + 1 + e.overflow = clear << 1 + for i := range e.table { + e.table[i] = invalidEntry + } + return errOutOfCodes + } + return nil +} + +// Write writes a compressed representation of p to e's underlying writer. +func (e *encoder) Write(p []byte) (n int, err error) { + if e.err != nil { + return 0, e.err + } + if len(p) == 0 { + return 0, nil + } + if maxLit := uint8(1< maxLit { + e.err = errors.New("lzw: input byte too large for the litWidth") + return 0, e.err + } + } + } + + n = len(p) + code := e.savedCode + if code == invalidCode { + // The first code sent is always a literal code. + code, p = uint32(p[0]), p[1:] + } +loop: + for _, x := range p { + literal := uint32(x) + key := code<<8 | literal + // If there is a hash table hit for this key then we continue the loop + // and do not emit a code yet. + hash := (key>>12 ^ key) & tableMask + for h, t := hash, e.table[hash]; t != invalidEntry; { + if key == t>>12 { + code = t & maxCode + continue loop + } + h = (h + 1) & tableMask + t = e.table[h] + } + // Otherwise, write the current code, and literal becomes the start of + // the next emitted code. + if e.err = e.write(e, code); e.err != nil { + return 0, e.err + } + code = literal + // Increment e.hi, the next implied code. If we run out of codes, reset + // the encoder state (including clearing the hash table) and continue. + if err1 := e.incHi(); err1 != nil { + if err1 == errOutOfCodes { + continue + } + e.err = err1 + return 0, e.err + } + // Otherwise, insert key -> e.hi into the map that e.table represents. + for { + if e.table[hash] == invalidEntry { + e.table[hash] = (key << 12) | e.hi + break + } + hash = (hash + 1) & tableMask + } + } + e.savedCode = code + return n, nil +} + +// Close closes the encoder, flushing any pending output. It does not close or +// flush e's underlying writer. +func (e *encoder) Close() error { + if e.err != nil { + if e.err == errClosed { + return nil + } + return e.err + } + // Make any future calls to Write return errClosed. + e.err = errClosed + // Write the savedCode if valid. + if e.savedCode != invalidCode { + if err := e.write(e, e.savedCode); err != nil { + return err + } + if err := e.incHi(); err != nil && err != errOutOfCodes { + return err + } + } + // Write the eof code. + eof := uint32(1)< 0 { + e.bits >>= 24 + if err := e.w.WriteByte(uint8(e.bits)); err != nil { + return err + } + } + return e.w.Flush() +} + +// NewWriter creates a new io.WriteCloser. +// Writes to the returned io.WriteCloser are compressed and written to w. +// It is the caller's responsibility to call Close on the WriteCloser when +// finished writing. +// oneOff makes code length increases occur one code early. It should be true +// for LZWDecode filters with earlyChange=1 which is also the default. +func NewWriter(w io.Writer, oneOff bool) io.WriteCloser { + + bw, ok := w.(writer) + if !ok { + bw = bufio.NewWriter(w) + } + + lw := uint(8) + + e := encoder{ + w: bw, + write: (*encoder).writeMSB, + litWidth: lw, + width: 1 + lw, + hi: 1< m { + if end > cap(b.buf) { + newcap := 1024 + for newcap < end { + newcap *= 2 + } + newbuf := make([]byte, end, newcap) + copy(newbuf, b.buf) + b.buf = newbuf + } else { + b.buf = b.buf[:end] + } + if n, err := io.ReadFull(b.r, b.buf[m:end]); err != nil { + end = m + n + b.buf = b.buf[:end] + return err + } + } + return nil +} + +func (b *buffer) ReadAt(p []byte, off int64) (int, error) { + o := int(off) + end := o + len(p) + if int64(end) != off+int64(len(p)) { + return 0, io.ErrUnexpectedEOF + } + + err := b.fill(end) + return copy(p, b.buf[o:end]), err +} + +// Slice returns a slice of the underlying buffer. The slice contains +// n bytes starting at offset off. +func (b *buffer) Slice(off, n int) ([]byte, error) { + end := off + n + if err := b.fill(end); err != nil { + return nil, err + } + return b.buf[off:end], nil +} + +// newReaderAt converts an io.Reader into an io.ReaderAt. +func newReaderAt(r io.Reader) io.ReaderAt { + if ra, ok := r.(io.ReaderAt); ok { + return ra + } + return &buffer{ + r: r, + buf: make([]byte, 0, 1024), + } +} diff --git a/vendor/github.com/hhrutter/tiff/compress.go b/vendor/github.com/hhrutter/tiff/compress.go new file mode 100644 index 0000000..3f176f0 --- /dev/null +++ b/vendor/github.com/hhrutter/tiff/compress.go @@ -0,0 +1,58 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tiff + +import ( + "bufio" + "io" +) + +type byteReader interface { + io.Reader + io.ByteReader +} + +// unpackBits decodes the PackBits-compressed data in src and returns the +// uncompressed data. +// +// The PackBits compression format is described in section 9 (p. 42) +// of the TIFF spec. +func unpackBits(r io.Reader) ([]byte, error) { + buf := make([]byte, 128) + dst := make([]byte, 0, 1024) + br, ok := r.(byteReader) + if !ok { + br = bufio.NewReader(r) + } + + for { + b, err := br.ReadByte() + if err != nil { + if err == io.EOF { + return dst, nil + } + return nil, err + } + code := int(int8(b)) + switch { + case code >= 0: + n, err := io.ReadFull(br, buf[:code+1]) + if err != nil { + return nil, err + } + dst = append(dst, buf[:n]...) + case code == -128: + // No-op. + default: + if b, err = br.ReadByte(); err != nil { + return nil, err + } + for j := 0; j < 1-code; j++ { + buf[j] = b + } + dst = append(dst, buf[:1-code]...) + } + } +} diff --git a/vendor/github.com/hhrutter/tiff/consts.go b/vendor/github.com/hhrutter/tiff/consts.go new file mode 100644 index 0000000..3e5f7f1 --- /dev/null +++ b/vendor/github.com/hhrutter/tiff/consts.go @@ -0,0 +1,149 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tiff + +// A tiff image file contains one or more images. The metadata +// of each image is contained in an Image File Directory (IFD), +// which contains entries of 12 bytes each and is described +// on page 14-16 of the specification. An IFD entry consists of +// +// - a tag, which describes the signification of the entry, +// - the data type and length of the entry, +// - the data itself or a pointer to it if it is more than 4 bytes. +// +// The presence of a length means that each IFD is effectively an array. + +const ( + leHeader = "II\x2A\x00" // Header for little-endian files. + beHeader = "MM\x00\x2A" // Header for big-endian files. + + ifdLen = 12 // Length of an IFD entry in bytes. +) + +// Data types (p. 14-16 of the spec). +const ( + dtByte = 1 + dtASCII = 2 + dtShort = 3 + dtLong = 4 + dtRational = 5 +) + +// The length of one instance of each data type in bytes. +var lengths = [...]uint32{0, 1, 1, 2, 4, 8} + +// Tags (see p. 28-41 of the spec). +const ( + tImageWidth = 256 + tImageLength = 257 + tBitsPerSample = 258 + tCompression = 259 + tPhotometricInterpretation = 262 + + tFillOrder = 266 + + tStripOffsets = 273 + tSamplesPerPixel = 277 + tRowsPerStrip = 278 + tStripByteCounts = 279 + + tT4Options = 292 // CCITT Group 3 options, a set of 32 flag bits. + tT6Options = 293 // CCITT Group 4 options, a set of 32 flag bits. + + tTileWidth = 322 + tTileLength = 323 + tTileOffsets = 324 + tTileByteCounts = 325 + + tXResolution = 282 + tYResolution = 283 + tResolutionUnit = 296 + + tPredictor = 317 + tColorMap = 320 + tExtraSamples = 338 + tSampleFormat = 339 +) + +// Compression types (defined in various places in the spec and supplements). +const ( + cNone = 1 + cCCITT = 2 + cG3 = 3 // Group 3 Fax. + cG4 = 4 // Group 4 Fax. + cLZW = 5 + cJPEGOld = 6 // Superseded by cJPEG. + cJPEG = 7 + cDeflate = 8 // zlib compression. + cPackBits = 32773 + cDeflateOld = 32946 // Superseded by cDeflate. +) + +// Photometric interpretation values (see p. 37 of the spec). +const ( + pWhiteIsZero = 0 + pBlackIsZero = 1 + pRGB = 2 + pPaletted = 3 + pTransMask = 4 // transparency mask + pCMYK = 5 + pYCbCr = 6 + pCIELab = 8 +) + +// Values for the tPredictor tag (page 64-65 of the spec). +const ( + prNone = 1 + prHorizontal = 2 +) + +// Values for the tResolutionUnit tag (page 18). +const ( + resNone = 1 + resPerInch = 2 // Dots per inch. + resPerCM = 3 // Dots per centimeter. +) + +// imageMode represents the mode of the image. +type imageMode int + +const ( + mBilevel imageMode = iota + mPaletted + mGray + mGrayInvert + mRGB + mRGBA + mNRGBA + mCMYK +) + +// CompressionType describes the type of compression used in Options. +type CompressionType int + +// Constants for supported compression types. +const ( + Uncompressed CompressionType = iota + Deflate + LZW + CCITTGroup3 + CCITTGroup4 +) + +// specValue returns the compression type constant from the TIFF spec that +// is equivalent to c. +func (c CompressionType) specValue() uint32 { + switch c { + case LZW: + return cLZW + case Deflate: + return cDeflate + case CCITTGroup3: + return cG3 + case CCITTGroup4: + return cG4 + } + return cNone +} diff --git a/vendor/github.com/hhrutter/tiff/go.mod b/vendor/github.com/hhrutter/tiff/go.mod new file mode 100644 index 0000000..a2367a4 --- /dev/null +++ b/vendor/github.com/hhrutter/tiff/go.mod @@ -0,0 +1,8 @@ +module github.com/hhrutter/tiff + +go 1.12 + +require ( + github.com/hhrutter/lzw v0.0.0-20190827003112-58b82c5a41cc + golang.org/x/image v0.0.0-20190823064033-3a9bac650e44 +) diff --git a/vendor/github.com/hhrutter/tiff/go.sum b/vendor/github.com/hhrutter/tiff/go.sum new file mode 100644 index 0000000..33a5b7f --- /dev/null +++ b/vendor/github.com/hhrutter/tiff/go.sum @@ -0,0 +1,6 @@ +github.com/hhrutter/lzw v0.0.0-20190826233241-e4e67a6cc9b8 h1:U1DNFAgO5OSS70hFTvB7PN/Ex0mhqC7cZZ4FUaNJ8F0= +github.com/hhrutter/lzw v0.0.0-20190827003112-58b82c5a41cc h1:crd+cScoxEqSOqClzjkNMNQNdMCF3SGXhPdDWBQfNZE= +github.com/hhrutter/lzw v0.0.0-20190827003112-58b82c5a41cc/go.mod h1:yJBvOcu1wLQ9q9XZmfiPfur+3dQJuIhYQsMGLYcItZk= +golang.org/x/image v0.0.0-20190823064033-3a9bac650e44 h1:1/e6LjNi7iqpDTz8tCLSKoR5dqrX4C3ub4H31JJZM4U= +golang.org/x/image v0.0.0-20190823064033-3a9bac650e44/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/hhrutter/tiff/reader.go b/vendor/github.com/hhrutter/tiff/reader.go new file mode 100644 index 0000000..ce05666 --- /dev/null +++ b/vendor/github.com/hhrutter/tiff/reader.go @@ -0,0 +1,735 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package tiff is an enhanced version of x/image/tiff. +// +// It uses a consolidated version of compress/lzw (https://github.com/hhrutter/lzw) for compression and also adds support for CMYK. +// +// More information: https://github.com/hhrutter/tiff +package tiff + +import ( + "compress/zlib" + "encoding/binary" + "fmt" + "image" + "image/color" + "io" + "io/ioutil" + "math" + + "github.com/hhrutter/lzw" + "golang.org/x/image/ccitt" +) + +// A FormatError reports that the input is not a valid TIFF image. +type FormatError string + +func (e FormatError) Error() string { + return "tiff: invalid format: " + string(e) +} + +// An UnsupportedError reports that the input uses a valid but +// unimplemented feature. +type UnsupportedError string + +func (e UnsupportedError) Error() string { + return "tiff: unsupported feature: " + string(e) +} + +var errNoPixels = FormatError("not enough pixel data") + +type decoder struct { + r io.ReaderAt + byteOrder binary.ByteOrder + config image.Config + mode imageMode + bpp uint + features map[int][]uint + palette []color.Color + + buf []byte + off int // Current offset in buf. + v uint32 // Buffer value for reading with arbitrary bit depths. + nbits uint // Remaining number of bits in v. +} + +// firstVal returns the first uint of the features entry with the given tag, +// or 0 if the tag does not exist. +func (d *decoder) firstVal(tag int) uint { + f := d.features[tag] + if len(f) == 0 { + return 0 + } + return f[0] +} + +// ifdUint decodes the IFD entry in p, which must be of the Byte, Short +// or Long type, and returns the decoded uint values. +func (d *decoder) ifdUint(p []byte) (u []uint, err error) { + var raw []byte + if len(p) < ifdLen { + return nil, FormatError("bad IFD entry") + } + + datatype := d.byteOrder.Uint16(p[2:4]) + if dt := int(datatype); dt <= 0 || dt >= len(lengths) { + return nil, UnsupportedError("IFD entry datatype") + } + + count := d.byteOrder.Uint32(p[4:8]) + if count > math.MaxInt32/lengths[datatype] { + return nil, FormatError("IFD data too large") + } + if datalen := lengths[datatype] * count; datalen > 4 { + // The IFD contains a pointer to the real value. + raw = make([]byte, datalen) + _, err = d.r.ReadAt(raw, int64(d.byteOrder.Uint32(p[8:12]))) + } else { + raw = p[8 : 8+datalen] + } + if err != nil { + return nil, err + } + + u = make([]uint, count) + switch datatype { + case dtByte: + for i := uint32(0); i < count; i++ { + u[i] = uint(raw[i]) + } + case dtShort: + for i := uint32(0); i < count; i++ { + u[i] = uint(d.byteOrder.Uint16(raw[2*i : 2*(i+1)])) + } + case dtLong: + for i := uint32(0); i < count; i++ { + u[i] = uint(d.byteOrder.Uint32(raw[4*i : 4*(i+1)])) + } + default: + return nil, UnsupportedError("data type") + } + return u, nil +} + +// parseIFD decides whether the the IFD entry in p is "interesting" and +// stows away the data in the decoder. It returns the tag number of the +// entry and an error, if any. +func (d *decoder) parseIFD(p []byte) (int, error) { + tag := d.byteOrder.Uint16(p[0:2]) + switch tag { + case tBitsPerSample, + tExtraSamples, + tPhotometricInterpretation, + tCompression, + tPredictor, + tStripOffsets, + tStripByteCounts, + tRowsPerStrip, + tTileWidth, + tTileLength, + tTileOffsets, + tTileByteCounts, + tImageLength, + tImageWidth, + tFillOrder, + tT4Options, + tT6Options: + val, err := d.ifdUint(p) + if err != nil { + return 0, err + } + d.features[int(tag)] = val + case tColorMap: + val, err := d.ifdUint(p) + if err != nil { + return 0, err + } + numcolors := len(val) / 3 + if len(val)%3 != 0 || numcolors <= 0 || numcolors > 256 { + return 0, FormatError("bad ColorMap length") + } + d.palette = make([]color.Color, numcolors) + for i := 0; i < numcolors; i++ { + d.palette[i] = color.RGBA64{ + uint16(val[i]), + uint16(val[i+numcolors]), + uint16(val[i+2*numcolors]), + 0xffff, + } + } + case tSampleFormat: + // Page 27 of the spec: If the SampleFormat is present and + // the value is not 1 [= unsigned integer data], a Baseline + // TIFF reader that cannot handle the SampleFormat value + // must terminate the import process gracefully. + val, err := d.ifdUint(p) + if err != nil { + return 0, err + } + for _, v := range val { + if v != 1 { + return 0, UnsupportedError("sample format") + } + } + } + return int(tag), nil +} + +// readBits reads n bits from the internal buffer starting at the current offset. +func (d *decoder) readBits(n uint) (v uint32, ok bool) { + for d.nbits < n { + d.v <<= 8 + if d.off >= len(d.buf) { + return 0, false + } + d.v |= uint32(d.buf[d.off]) + d.off++ + d.nbits += 8 + } + d.nbits -= n + rv := d.v >> d.nbits + d.v &^= rv << d.nbits + return rv, true +} + +// flushBits discards the unread bits in the buffer used by readBits. +// It is used at the end of a line. +func (d *decoder) flushBits() { + d.v = 0 + d.nbits = 0 +} + +// minInt returns the smaller of x or y. +func minInt(a, b int) int { + if a <= b { + return a + } + return b +} + +// decode decodes the raw data of an image. +// It reads from d.buf and writes the strip or tile into dst. +func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { + d.off = 0 + + // Apply horizontal predictor if necessary. + // In this case, p contains the color difference to the preceding pixel. + // See page 64-65 of the spec. + if d.firstVal(tPredictor) == prHorizontal { + switch d.bpp { + case 16: + var off int + n := 2 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel + for y := ymin; y < ymax; y++ { + off += n + for x := 0; x < (xmax-xmin-1)*n; x += 2 { + if off+2 > len(d.buf) { + return errNoPixels + } + v0 := d.byteOrder.Uint16(d.buf[off-n : off-n+2]) + v1 := d.byteOrder.Uint16(d.buf[off : off+2]) + d.byteOrder.PutUint16(d.buf[off:off+2], v1+v0) + off += 2 + } + } + case 8: + var off int + n := 1 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel + for y := ymin; y < ymax; y++ { + off += n + for x := 0; x < (xmax-xmin-1)*n; x++ { + if off >= len(d.buf) { + return errNoPixels + } + d.buf[off] += d.buf[off-n] + off++ + } + } + case 1: + return UnsupportedError("horizontal predictor with 1 BitsPerSample") + } + } + + rMaxX := minInt(xmax, dst.Bounds().Max.X) + rMaxY := minInt(ymax, dst.Bounds().Max.Y) + switch d.mode { + case mGray, mGrayInvert: + if d.bpp == 16 { + img := dst.(*image.Gray16) + for y := ymin; y < rMaxY; y++ { + for x := xmin; x < rMaxX; x++ { + if d.off+2 > len(d.buf) { + return errNoPixels + } + v := d.byteOrder.Uint16(d.buf[d.off : d.off+2]) + d.off += 2 + if d.mode == mGrayInvert { + v = 0xffff - v + } + img.SetGray16(x, y, color.Gray16{v}) + } + if rMaxX == img.Bounds().Max.X { + d.off += 2 * (xmax - img.Bounds().Max.X) + } + } + } else { + img := dst.(*image.Gray) + max := uint32((1 << d.bpp) - 1) + for y := ymin; y < rMaxY; y++ { + for x := xmin; x < rMaxX; x++ { + v, ok := d.readBits(d.bpp) + if !ok { + return errNoPixels + } + v = v * 0xff / max + if d.mode == mGrayInvert { + v = 0xff - v + } + img.SetGray(x, y, color.Gray{uint8(v)}) + } + d.flushBits() + } + } + case mPaletted: + img := dst.(*image.Paletted) + for y := ymin; y < rMaxY; y++ { + for x := xmin; x < rMaxX; x++ { + v, ok := d.readBits(d.bpp) + if !ok { + return errNoPixels + } + img.SetColorIndex(x, y, uint8(v)) + } + d.flushBits() + } + case mRGB: + if d.bpp == 16 { + img := dst.(*image.RGBA64) + for y := ymin; y < rMaxY; y++ { + for x := xmin; x < rMaxX; x++ { + if d.off+6 > len(d.buf) { + return errNoPixels + } + r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2]) + g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4]) + b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6]) + d.off += 6 + img.SetRGBA64(x, y, color.RGBA64{r, g, b, 0xffff}) + } + } + } else { + img := dst.(*image.RGBA) + for y := ymin; y < rMaxY; y++ { + min := img.PixOffset(xmin, y) + max := img.PixOffset(rMaxX, y) + off := (y - ymin) * (xmax - xmin) * 3 + for i := min; i < max; i += 4 { + if off+3 > len(d.buf) { + return errNoPixels + } + img.Pix[i+0] = d.buf[off+0] + img.Pix[i+1] = d.buf[off+1] + img.Pix[i+2] = d.buf[off+2] + img.Pix[i+3] = 0xff + off += 3 + } + } + } + case mNRGBA: + if d.bpp == 16 { + img := dst.(*image.NRGBA64) + for y := ymin; y < rMaxY; y++ { + for x := xmin; x < rMaxX; x++ { + if d.off+8 > len(d.buf) { + return errNoPixels + } + r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2]) + g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4]) + b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6]) + a := d.byteOrder.Uint16(d.buf[d.off+6 : d.off+8]) + d.off += 8 + img.SetNRGBA64(x, y, color.NRGBA64{r, g, b, a}) + } + } + } else { + img := dst.(*image.NRGBA) + for y := ymin; y < rMaxY; y++ { + min := img.PixOffset(xmin, y) + max := img.PixOffset(rMaxX, y) + i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4 + if i1 > len(d.buf) { + return errNoPixels + } + copy(img.Pix[min:max], d.buf[i0:i1]) + } + } + case mRGBA: + if d.bpp == 16 { + img := dst.(*image.RGBA64) + for y := ymin; y < rMaxY; y++ { + for x := xmin; x < rMaxX; x++ { + if d.off+8 > len(d.buf) { + return errNoPixels + } + r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2]) + g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4]) + b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6]) + a := d.byteOrder.Uint16(d.buf[d.off+6 : d.off+8]) + d.off += 8 + img.SetRGBA64(x, y, color.RGBA64{r, g, b, a}) + } + } + } else { + img := dst.(*image.RGBA) + for y := ymin; y < rMaxY; y++ { + min := img.PixOffset(xmin, y) + max := img.PixOffset(rMaxX, y) + i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4 + if i1 > len(d.buf) { + return errNoPixels + } + copy(img.Pix[min:max], d.buf[i0:i1]) + } + } + case mCMYK: + // d.bpp must be 8 + img := dst.(*image.CMYK) + for y := ymin; y < rMaxY; y++ { + min := img.PixOffset(xmin, y) + max := img.PixOffset(rMaxX, y) + i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4 + if i1 > len(d.buf) { + return errNoPixels + } + copy(img.Pix[min:max], d.buf[i0:i1]) + } + + } + + return nil +} + +func newDecoder(r io.Reader) (*decoder, error) { + d := &decoder{ + r: newReaderAt(r), + features: make(map[int][]uint), + } + + p := make([]byte, 8) + if _, err := d.r.ReadAt(p, 0); err != nil { + return nil, err + } + switch string(p[0:4]) { + case leHeader: + d.byteOrder = binary.LittleEndian + case beHeader: + d.byteOrder = binary.BigEndian + default: + return nil, FormatError("malformed header") + } + + ifdOffset := int64(d.byteOrder.Uint32(p[4:8])) + + // The first two bytes contain the number of entries (12 bytes each). + if _, err := d.r.ReadAt(p[0:2], ifdOffset); err != nil { + return nil, err + } + numItems := int(d.byteOrder.Uint16(p[0:2])) + + // All IFD entries are read in one chunk. + p = make([]byte, ifdLen*numItems) + if _, err := d.r.ReadAt(p, ifdOffset+2); err != nil { + return nil, err + } + + prevTag := -1 + for i := 0; i < len(p); i += ifdLen { + tag, err := d.parseIFD(p[i : i+ifdLen]) + if err != nil { + return nil, err + } + if tag <= prevTag { + return nil, FormatError("tags are not sorted in ascending order") + } + prevTag = tag + } + + d.config.Width = int(d.firstVal(tImageWidth)) + d.config.Height = int(d.firstVal(tImageLength)) + + if _, ok := d.features[tBitsPerSample]; !ok { + // Default is 1 per specification. + d.features[tBitsPerSample] = []uint{1} + } + d.bpp = d.firstVal(tBitsPerSample) + switch d.bpp { + case 0: + return nil, FormatError("BitsPerSample must not be 0") + case 1, 8, 16: + // Nothing to do, these are accepted by this implementation. + default: + return nil, UnsupportedError(fmt.Sprintf("BitsPerSample of %v", d.bpp)) + } + + // Determine the image mode. + switch d.firstVal(tPhotometricInterpretation) { + case pRGB: + if d.bpp == 16 { + for _, b := range d.features[tBitsPerSample] { + if b != 16 { + return nil, FormatError("wrong number of samples for 16bit RGB") + } + } + } else { + for _, b := range d.features[tBitsPerSample] { + if b != 8 { + return nil, FormatError("wrong number of samples for 8bit RGB") + } + } + } + // RGB images normally have 3 samples per pixel. + // If there are more, ExtraSamples (p. 31-32 of the spec) + // gives their meaning (usually an alpha channel). + // + // This implementation does not support extra samples + // of an unspecified type. + switch len(d.features[tBitsPerSample]) { + case 3: + d.mode = mRGB + if d.bpp == 16 { + d.config.ColorModel = color.RGBA64Model + } else { + d.config.ColorModel = color.RGBAModel + } + case 4: + switch d.firstVal(tExtraSamples) { + case 1: + d.mode = mRGBA + if d.bpp == 16 { + d.config.ColorModel = color.RGBA64Model + } else { + d.config.ColorModel = color.RGBAModel + } + case 2: + d.mode = mNRGBA + if d.bpp == 16 { + d.config.ColorModel = color.NRGBA64Model + } else { + d.config.ColorModel = color.NRGBAModel + } + default: + return nil, FormatError("wrong number of samples for RGB") + } + default: + return nil, FormatError("wrong number of samples for RGB") + } + case pPaletted: + d.mode = mPaletted + d.config.ColorModel = color.Palette(d.palette) + case pWhiteIsZero: + d.mode = mGrayInvert + if d.bpp == 16 { + d.config.ColorModel = color.Gray16Model + } else { + d.config.ColorModel = color.GrayModel + } + case pBlackIsZero: + d.mode = mGray + if d.bpp == 16 { + d.config.ColorModel = color.Gray16Model + } else { + d.config.ColorModel = color.GrayModel + } + case pCMYK: + d.mode = mCMYK + if d.bpp == 16 { + return nil, UnsupportedError(fmt.Sprintf("CMYK BitsPerSample of %v", d.bpp)) + } + d.config.ColorModel = color.CMYKModel + + default: + return nil, UnsupportedError("color model") + } + + return d, nil +} + +// DecodeConfig returns the color model and dimensions of a TIFF image without +// decoding the entire image. +func DecodeConfig(r io.Reader) (image.Config, error) { + d, err := newDecoder(r) + if err != nil { + return image.Config{}, err + } + return d.config, nil +} + +func ccittFillOrder(tiffFillOrder uint) ccitt.Order { + if tiffFillOrder == 2 { + return ccitt.LSB + } + return ccitt.MSB +} + +// Decode reads a TIFF image from r and returns it as an image.Image. +// The type of Image returned depends on the contents of the TIFF. +func Decode(r io.Reader) (img image.Image, err error) { + d, err := newDecoder(r) + if err != nil { + return + } + + blockPadding := false + blockWidth := d.config.Width + blockHeight := d.config.Height + blocksAcross := 1 + blocksDown := 1 + + if d.config.Width == 0 { + blocksAcross = 0 + } + if d.config.Height == 0 { + blocksDown = 0 + } + + var blockOffsets, blockCounts []uint + + if int(d.firstVal(tTileWidth)) != 0 { + blockPadding = true + + blockWidth = int(d.firstVal(tTileWidth)) + blockHeight = int(d.firstVal(tTileLength)) + + if blockWidth != 0 { + blocksAcross = (d.config.Width + blockWidth - 1) / blockWidth + } + if blockHeight != 0 { + blocksDown = (d.config.Height + blockHeight - 1) / blockHeight + } + + blockCounts = d.features[tTileByteCounts] + blockOffsets = d.features[tTileOffsets] + + } else { + if int(d.firstVal(tRowsPerStrip)) != 0 { + blockHeight = int(d.firstVal(tRowsPerStrip)) + } + + if blockHeight != 0 { + blocksDown = (d.config.Height + blockHeight - 1) / blockHeight + } + + blockOffsets = d.features[tStripOffsets] + blockCounts = d.features[tStripByteCounts] + } + + // Check if we have the right number of strips/tiles, offsets and counts. + if n := blocksAcross * blocksDown; len(blockOffsets) < n || len(blockCounts) < n { + return nil, FormatError("inconsistent header") + } + + imgRect := image.Rect(0, 0, d.config.Width, d.config.Height) + switch d.mode { + case mGray, mGrayInvert: + if d.bpp == 16 { + img = image.NewGray16(imgRect) + } else { + img = image.NewGray(imgRect) + } + case mPaletted: + img = image.NewPaletted(imgRect, d.palette) + case mNRGBA: + if d.bpp == 16 { + img = image.NewNRGBA64(imgRect) + } else { + img = image.NewNRGBA(imgRect) + } + case mRGB, mRGBA: + if d.bpp == 16 { + img = image.NewRGBA64(imgRect) + } else { + img = image.NewRGBA(imgRect) + } + case mCMYK: + img = image.NewCMYK(imgRect) + } + + for i := 0; i < blocksAcross; i++ { + blkW := blockWidth + if !blockPadding && i == blocksAcross-1 && d.config.Width%blockWidth != 0 { + blkW = d.config.Width % blockWidth + } + for j := 0; j < blocksDown; j++ { + blkH := blockHeight + if !blockPadding && j == blocksDown-1 && d.config.Height%blockHeight != 0 { + blkH = d.config.Height % blockHeight + } + offset := int64(blockOffsets[j*blocksAcross+i]) + n := int64(blockCounts[j*blocksAcross+i]) + // LSBToMSB := d.firstVal(tFillOrder) == 2 + // order := ccitt.MSB + // if LSBToMSB { + // order = ccitt.LSB + // } + switch d.firstVal(tCompression) { + + // According to the spec, Compression does not have a default value, + // but some tools interpret a missing Compression value as none so we do + // the same. + case cNone, 0: + if b, ok := d.r.(*buffer); ok { + d.buf, err = b.Slice(int(offset), int(n)) + } else { + d.buf = make([]byte, n) + _, err = d.r.ReadAt(d.buf, offset) + } + case cG3: + inv := d.firstVal(tPhotometricInterpretation) == pWhiteIsZero + order := ccittFillOrder(d.firstVal(tFillOrder)) + r := ccitt.NewReader(io.NewSectionReader(d.r, offset, n), order, ccitt.Group3, blkW, blkH, &ccitt.Options{Invert: inv, Align: false}) + d.buf, err = ioutil.ReadAll(r) + case cG4: + inv := d.firstVal(tPhotometricInterpretation) == pWhiteIsZero + order := ccittFillOrder(d.firstVal(tFillOrder)) + r := ccitt.NewReader(io.NewSectionReader(d.r, offset, n), order, ccitt.Group4, blkW, blkH, &ccitt.Options{Invert: inv, Align: false}) + d.buf, err = ioutil.ReadAll(r) + case cLZW: + r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), true) + d.buf, err = ioutil.ReadAll(r) + r.Close() + case cDeflate, cDeflateOld: + var r io.ReadCloser + r, err = zlib.NewReader(io.NewSectionReader(d.r, offset, n)) + if err != nil { + return nil, err + } + d.buf, err = ioutil.ReadAll(r) + r.Close() + case cPackBits: + d.buf, err = unpackBits(io.NewSectionReader(d.r, offset, n)) + default: + err = UnsupportedError(fmt.Sprintf("compression value %d", d.firstVal(tCompression))) + } + if err != nil { + return nil, err + } + + xmin := i * blockWidth + ymin := j * blockHeight + xmax := xmin + blkW + ymax := ymin + blkH + err = d.decode(img, xmin, ymin, xmax, ymax) + if err != nil { + return nil, err + } + } + } + return +} + +func init() { + image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig) + image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig) +} diff --git a/vendor/github.com/hhrutter/tiff/writer.go b/vendor/github.com/hhrutter/tiff/writer.go new file mode 100644 index 0000000..47d71fc --- /dev/null +++ b/vendor/github.com/hhrutter/tiff/writer.go @@ -0,0 +1,482 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tiff + +import ( + "bytes" + "compress/zlib" + "encoding/binary" + "fmt" + "image" + "io" + "sort" + + "github.com/hhrutter/lzw" +) + +// The TIFF format allows to choose the order of the different elements freely. +// The basic structure of a TIFF file written by this package is: +// +// 1. Header (8 bytes). +// 2. Image data. +// 3. Image File Directory (IFD). +// 4. "Pointer area" for larger entries in the IFD. + +// We only write little-endian TIFF files. +var enc = binary.LittleEndian + +// An ifdEntry is a single entry in an Image File Directory. +// A value of type dtRational is composed of two 32-bit values, +// thus data contains two uints (numerator and denominator) for a single number. +type ifdEntry struct { + tag int + datatype int + data []uint32 +} + +func (e ifdEntry) putData(p []byte) { + for _, d := range e.data { + switch e.datatype { + case dtByte, dtASCII: + p[0] = byte(d) + p = p[1:] + case dtShort: + enc.PutUint16(p, uint16(d)) + p = p[2:] + case dtLong, dtRational: + enc.PutUint32(p, uint32(d)) + p = p[4:] + } + } +} + +type byTag []ifdEntry + +func (d byTag) Len() int { return len(d) } +func (d byTag) Less(i, j int) bool { return d[i].tag < d[j].tag } +func (d byTag) Swap(i, j int) { d[i], d[j] = d[j], d[i] } + +func encodeGray(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error { + if !predictor { + return writePix(w, pix, dy, dx, stride) + } + buf := make([]byte, dx) + for y := 0; y < dy; y++ { + min := y*stride + 0 + max := y*stride + dx + off := 0 + var v0 uint8 + for i := min; i < max; i++ { + v1 := pix[i] + buf[off] = v1 - v0 + v0 = v1 + off++ + } + if _, err := w.Write(buf); err != nil { + return err + } + } + return nil +} + +func encodeGray16(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error { + buf := make([]byte, dx*2) + for y := 0; y < dy; y++ { + min := y*stride + 0 + max := y*stride + dx*2 + off := 0 + var v0 uint16 + for i := min; i < max; i += 2 { + // An image.Gray16's Pix is in big-endian order. + v1 := uint16(pix[i])<<8 | uint16(pix[i+1]) + if predictor { + v0, v1 = v1, v1-v0 + } + // We only write little-endian TIFF files. + buf[off+0] = byte(v1) + buf[off+1] = byte(v1 >> 8) + off += 2 + } + if _, err := w.Write(buf); err != nil { + return err + } + } + return nil +} + +func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error { + if !predictor { + return writePix(w, pix, dy, dx*4, stride) + } + buf := make([]byte, dx*4) + for y := 0; y < dy; y++ { + min := y*stride + 0 + max := y*stride + dx*4 + off := 0 + var r0, g0, b0, a0 uint8 + for i := min; i < max; i += 4 { + r1, g1, b1, a1 := pix[i+0], pix[i+1], pix[i+2], pix[i+3] + buf[off+0] = r1 - r0 + buf[off+1] = g1 - g0 + buf[off+2] = b1 - b0 + buf[off+3] = a1 - a0 + off += 4 + r0, g0, b0, a0 = r1, g1, b1, a1 + } + if _, err := w.Write(buf); err != nil { + return err + } + } + return nil +} + +func encodeRGBA64(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error { + buf := make([]byte, dx*8) + for y := 0; y < dy; y++ { + min := y*stride + 0 + max := y*stride + dx*8 + off := 0 + var r0, g0, b0, a0 uint16 + for i := min; i < max; i += 8 { + // An image.RGBA64's Pix is in big-endian order. + r1 := uint16(pix[i+0])<<8 | uint16(pix[i+1]) + g1 := uint16(pix[i+2])<<8 | uint16(pix[i+3]) + b1 := uint16(pix[i+4])<<8 | uint16(pix[i+5]) + a1 := uint16(pix[i+6])<<8 | uint16(pix[i+7]) + if predictor { + r0, r1 = r1, r1-r0 + g0, g1 = g1, g1-g0 + b0, b1 = b1, b1-b0 + a0, a1 = a1, a1-a0 + } + // We only write little-endian TIFF files. + buf[off+0] = byte(r1) + buf[off+1] = byte(r1 >> 8) + buf[off+2] = byte(g1) + buf[off+3] = byte(g1 >> 8) + buf[off+4] = byte(b1) + buf[off+5] = byte(b1 >> 8) + buf[off+6] = byte(a1) + buf[off+7] = byte(a1 >> 8) + off += 8 + } + if _, err := w.Write(buf); err != nil { + return err + } + } + return nil +} + +func encodeCMYK(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error { + if !predictor { + return writePix(w, pix, dy, dx*4, stride) + } + buf := make([]byte, dx*4) + for y := 0; y < dy; y++ { + min := y*stride + 0 + max := y*stride + dx*4 + off := 0 + var c0, m0, y0, k0 uint8 + for i := min; i < max; i += 4 { + c1, m1, y1, k1 := pix[i+0], pix[i+1], pix[i+2], pix[i+3] + buf[off+0] = c1 - c0 + buf[off+1] = m1 - m0 + buf[off+2] = y1 - y0 + buf[off+3] = k1 - k0 + off += 4 + c0, m0, y0, k0 = c1, m1, y1, k1 + } + if _, err := w.Write(buf); err != nil { + return err + } + } + return nil +} + +func encode(w io.Writer, m image.Image, predictor bool) error { + bounds := m.Bounds() + buf := make([]byte, 4*bounds.Dx()) + for y := bounds.Min.Y; y < bounds.Max.Y; y++ { + off := 0 + if predictor { + var r0, g0, b0, a0 uint8 + for x := bounds.Min.X; x < bounds.Max.X; x++ { + r, g, b, a := m.At(x, y).RGBA() + r1 := uint8(r >> 8) + g1 := uint8(g >> 8) + b1 := uint8(b >> 8) + a1 := uint8(a >> 8) + buf[off+0] = r1 - r0 + buf[off+1] = g1 - g0 + buf[off+2] = b1 - b0 + buf[off+3] = a1 - a0 + off += 4 + r0, g0, b0, a0 = r1, g1, b1, a1 + } + } else { + for x := bounds.Min.X; x < bounds.Max.X; x++ { + r, g, b, a := m.At(x, y).RGBA() + buf[off+0] = uint8(r >> 8) + buf[off+1] = uint8(g >> 8) + buf[off+2] = uint8(b >> 8) + buf[off+3] = uint8(a >> 8) + off += 4 + } + } + if _, err := w.Write(buf); err != nil { + return err + } + } + return nil +} + +// writePix writes the internal byte array of an image to w. It is less general +// but much faster then encode. writePix is used when pix directly +// corresponds to one of the TIFF image types. +func writePix(w io.Writer, pix []byte, nrows, length, stride int) error { + if length == stride { + _, err := w.Write(pix[:nrows*length]) + return err + } + for ; nrows > 0; nrows-- { + if _, err := w.Write(pix[:length]); err != nil { + return err + } + pix = pix[stride:] + } + return nil +} + +func writeIFD(w io.Writer, ifdOffset int, d []ifdEntry) error { + var buf [ifdLen]byte + // Make space for "pointer area" containing IFD entry data + // longer than 4 bytes. + parea := make([]byte, 1024) + pstart := ifdOffset + ifdLen*len(d) + 6 + var o int // Current offset in parea. + + // The IFD has to be written with the tags in ascending order. + sort.Sort(byTag(d)) + + // Write the number of entries in this IFD. + if err := binary.Write(w, enc, uint16(len(d))); err != nil { + return err + } + for _, ent := range d { + enc.PutUint16(buf[0:2], uint16(ent.tag)) + enc.PutUint16(buf[2:4], uint16(ent.datatype)) + count := uint32(len(ent.data)) + if ent.datatype == dtRational { + count /= 2 + } + enc.PutUint32(buf[4:8], count) + datalen := int(count * lengths[ent.datatype]) + if datalen <= 4 { + ent.putData(buf[8:12]) + } else { + if (o + datalen) > len(parea) { + newlen := len(parea) + 1024 + for (o + datalen) > newlen { + newlen += 1024 + } + newarea := make([]byte, newlen) + copy(newarea, parea) + parea = newarea + } + ent.putData(parea[o : o+datalen]) + enc.PutUint32(buf[8:12], uint32(pstart+o)) + o += datalen + } + if _, err := w.Write(buf[:]); err != nil { + return err + } + } + // The IFD ends with the offset of the next IFD in the file, + // or zero if it is the last one (page 14). + if err := binary.Write(w, enc, uint32(0)); err != nil { + return err + } + _, err := w.Write(parea[:o]) + return err +} + +// Options are the encoding parameters. +type Options struct { + // Compression is the type of compression used. + Compression CompressionType + // Predictor determines whether a differencing predictor is used; + // if true, instead of each pixel's color, the color difference to the + // preceding one is saved. This improves the compression for certain + // types of images and compressors. For example, it works well for + // photos with Deflate compression. + Predictor bool +} + +// Encode writes the image m to w. opt determines the options used for +// encoding, such as the compression type. If opt is nil, an uncompressed +// image is written. +func Encode(w io.Writer, m image.Image, opt *Options) error { + d := m.Bounds().Size() + + compression := uint32(cNone) + predictor := false + if opt != nil { + compression = opt.Compression.specValue() + // The TIFF 6.0 spec (June,1992) says the predictor field is only to be used with LZW. (See page 64). + // Yet this TIFF writer also allows prediction for Deflate compression. + // This makes sense as Deflate is supposedly the successor to LWZ. + // Also both PNG and PDF use Deflate with predictors. + predictor = opt.Predictor && compression == cLZW || compression == cDeflate + } + + _, err := io.WriteString(w, leHeader) + if err != nil { + return err + } + + // Compressed data is written into a buffer first, so that we + // know the compressed size. + var buf bytes.Buffer + // dst holds the destination for the pixel data of the image -- + // either w or a writer to buf. + var dst io.Writer + // imageLen is the length of the pixel data in bytes. + // The offset of the IFD is imageLen + 8 header bytes. + var imageLen int + + switch compression { + case cNone: + dst = w + // Write IFD offset before outputting pixel data. + switch m.(type) { + case *image.Paletted: + imageLen = d.X * d.Y * 1 + case *image.Gray: + imageLen = d.X * d.Y * 1 + case *image.Gray16: + imageLen = d.X * d.Y * 2 + case *image.RGBA64: + imageLen = d.X * d.Y * 8 + case *image.NRGBA64: + imageLen = d.X * d.Y * 8 + case *image.CMYK: + imageLen = d.X * d.Y * 4 + default: + imageLen = d.X * d.Y * 4 + } + err = binary.Write(w, enc, uint32(imageLen+8)) + case cLZW: + dst = lzw.NewWriter(&buf, true) + case cDeflate: + dst = zlib.NewWriter(&buf) + default: + err = UnsupportedError(fmt.Sprintf("compression value %d", compression)) + } + + if err != nil { + return err + } + + pr := uint32(prNone) + photometricInterpretation := uint32(pRGB) + samplesPerPixel := uint32(4) + bitsPerSample := []uint32{8, 8, 8, 8} + extraSamples := uint32(0) + colorMap := []uint32{} + + if predictor { + pr = prHorizontal + } + switch m := m.(type) { + case *image.Paletted: + photometricInterpretation = pPaletted + samplesPerPixel = 1 + bitsPerSample = []uint32{8} + colorMap = make([]uint32, 256*3) + for i := 0; i < 256 && i < len(m.Palette); i++ { + r, g, b, _ := m.Palette[i].RGBA() + colorMap[i+0*256] = uint32(r) + colorMap[i+1*256] = uint32(g) + colorMap[i+2*256] = uint32(b) + } + err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor) + case *image.Gray: + photometricInterpretation = pBlackIsZero + samplesPerPixel = 1 + bitsPerSample = []uint32{8} + err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor) + case *image.Gray16: + photometricInterpretation = pBlackIsZero + samplesPerPixel = 1 + bitsPerSample = []uint32{16} + err = encodeGray16(dst, m.Pix, d.X, d.Y, m.Stride, predictor) + case *image.NRGBA: + extraSamples = 2 // Unassociated alpha. + err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor) + case *image.NRGBA64: + extraSamples = 2 // Unassociated alpha. + bitsPerSample = []uint32{16, 16, 16, 16} + err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor) + case *image.RGBA: + extraSamples = 1 // Associated alpha. + err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor) + case *image.RGBA64: + extraSamples = 1 // Associated alpha. + bitsPerSample = []uint32{16, 16, 16, 16} + err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor) + case *image.CMYK: + photometricInterpretation = uint32(pCMYK) + samplesPerPixel = uint32(4) + bitsPerSample = []uint32{8, 8, 8, 8} + err = encodeCMYK(dst, m.Pix, d.X, d.Y, m.Stride, predictor) + default: + extraSamples = 1 // Associated alpha. + err = encode(dst, m, predictor) + } + if err != nil { + return err + } + + if compression != cNone { + if err = dst.(io.Closer).Close(); err != nil { + return err + } + imageLen = buf.Len() + if err = binary.Write(w, enc, uint32(imageLen+8)); err != nil { + return err + } + if _, err = buf.WriteTo(w); err != nil { + return err + } + } + + ifd := []ifdEntry{ + {tImageWidth, dtShort, []uint32{uint32(d.X)}}, + {tImageLength, dtShort, []uint32{uint32(d.Y)}}, + {tBitsPerSample, dtShort, bitsPerSample}, + {tCompression, dtShort, []uint32{compression}}, + {tPhotometricInterpretation, dtShort, []uint32{photometricInterpretation}}, + {tStripOffsets, dtLong, []uint32{8}}, + {tSamplesPerPixel, dtShort, []uint32{samplesPerPixel}}, + {tRowsPerStrip, dtShort, []uint32{uint32(d.Y)}}, + {tStripByteCounts, dtLong, []uint32{uint32(imageLen)}}, + // There is currently no support for storing the image + // resolution, so give a bogus value of 72x72 dpi. + {tXResolution, dtRational, []uint32{72, 1}}, + {tYResolution, dtRational, []uint32{72, 1}}, + {tResolutionUnit, dtShort, []uint32{resPerInch}}, + } + if pr != prNone { + ifd = append(ifd, ifdEntry{tPredictor, dtShort, []uint32{pr}}) + } + if len(colorMap) != 0 { + ifd = append(ifd, ifdEntry{tColorMap, dtShort, colorMap}) + } + if extraSamples > 0 { + ifd = append(ifd, ifdEntry{tExtraSamples, dtShort, []uint32{extraSamples}}) + } + + return writeIFD(w, imageLen+8, ifd) +} diff --git a/vendor/github.com/muun/libwallet/.gitignore b/vendor/github.com/muun/libwallet/.gitignore index fa7ba6e..8e6d377 100644 --- a/vendor/github.com/muun/libwallet/.gitignore +++ b/vendor/github.com/muun/libwallet/.gitignore @@ -1,3 +1,4 @@ libwallet/.gitignore# binary libwallet +.build diff --git a/vendor/github.com/muun/libwallet/V1.go b/vendor/github.com/muun/libwallet/V1.go index 444dc82..ef04a46 100644 --- a/vendor/github.com/muun/libwallet/V1.go +++ b/vendor/github.com/muun/libwallet/V1.go @@ -1,12 +1,13 @@ package libwallet import ( + "fmt" + "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/muun/libwallet/addresses" - "github.com/pkg/errors" ) // CreateAddressV1 returns a P2PKH MuunAddress from a publicKey for use in TransactionSchemeV1 @@ -23,12 +24,12 @@ type coinV1 struct { func (c *coinV1) SignInput(index int, tx *wire.MsgTx, userKey *HDPrivateKey, _ *HDPublicKey) error { userKey, err := userKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive user key") + return fmt.Errorf("failed to derive user key: %w", err) } sig, err := c.signature(index, tx, userKey) if err != nil { - return errors.Wrapf(err, "failed to sign V1 input") + return fmt.Errorf("failed to sign V1 input: %w", err) } builder := txscript.NewScriptBuilder() @@ -36,7 +37,7 @@ func (c *coinV1) SignInput(index int, tx *wire.MsgTx, userKey *HDPrivateKey, _ * builder.AddData(userKey.PublicKey().Raw()) script, err := builder.Script() if err != nil { - return errors.Wrapf(err, "failed to generate signing script") + return fmt.Errorf("failed to generate signing script: %w", err) } txInput := tx.TxIn[index] @@ -52,7 +53,7 @@ func (c *coinV1) createRedeemScript(publicKey *HDPublicKey) ([]byte, error) { userAddress, err := btcutil.NewAddressPubKey(publicKey.Raw(), c.Network) if err != nil { - return nil, errors.Wrapf(err, "failed to generate address for user") + return nil, fmt.Errorf("failed to generate address for user: %w", err) } return txscript.PayToAddrScript(userAddress.AddressPubKeyHash()) @@ -62,17 +63,17 @@ func (c *coinV1) signature(index int, tx *wire.MsgTx, userKey *HDPrivateKey) ([] redeemScript, err := c.createRedeemScript(userKey.PublicKey()) if err != nil { - return nil, errors.Wrapf(err, "failed to build reedem script for signing") + return nil, fmt.Errorf("failed to build reedem script for signing: %w", err) } privKey, err := userKey.key.ECPrivKey() if err != nil { - return nil, errors.Wrapf(err, "failed to produce EC priv key for signing") + return nil, fmt.Errorf("failed to produce EC priv key for signing: %w", err) } sig, err := txscript.RawTxInSignature(tx, index, redeemScript, txscript.SigHashAll, privKey) if err != nil { - return nil, errors.Wrapf(err, "failed to sign V1 input") + return nil, fmt.Errorf("failed to sign V1 input: %w", err) } return sig, nil diff --git a/vendor/github.com/muun/libwallet/V2.go b/vendor/github.com/muun/libwallet/V2.go index e3f6f2b..efacd44 100644 --- a/vendor/github.com/muun/libwallet/V2.go +++ b/vendor/github.com/muun/libwallet/V2.go @@ -1,10 +1,12 @@ package libwallet import ( + "errors" + "fmt" + "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/txscript" "github.com/muun/libwallet/addresses" - "github.com/pkg/errors" "github.com/btcsuite/btcd/wire" ) @@ -24,23 +26,23 @@ type coinV2 struct { func (c *coinV2) SignInput(index int, tx *wire.MsgTx, userKey *HDPrivateKey, muunKey *HDPublicKey) error { userKey, err := userKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive user key") + return fmt.Errorf("failed to derive user key: %w", err) } muunKey, err = muunKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive muun key") + return fmt.Errorf("failed to derive muun key: %w", err) } if len(c.MuunSignature) == 0 { - return errors.Errorf("muun signature must be present") + return errors.New("muun signature must be present") } txInput := tx.TxIn[index] redeemScript, err := createRedeemScriptV2(userKey.PublicKey(), muunKey) if err != nil { - return errors.Wrapf(err, "failed to build reedem script for signing") + return fmt.Errorf("failed to build reedem script for signing: %w", err) } sig, err := c.signature(index, tx, userKey.PublicKey(), muunKey, userKey) @@ -59,7 +61,7 @@ func (c *coinV2) SignInput(index int, tx *wire.MsgTx, userKey *HDPrivateKey, muu builder.AddData(redeemScript) script, err := builder.Script() if err != nil { - return errors.Wrapf(err, "failed to generate signing script") + return fmt.Errorf("failed to generate signing script: %w", err) } txInput.SignatureScript = script @@ -71,12 +73,12 @@ func (c *coinV2) FullySignInput(index int, tx *wire.MsgTx, userKey, muunKey *HDP derivedUserKey, err := userKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive user key") + return fmt.Errorf("failed to derive user key: %w", err) } derivedMuunKey, err := muunKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive muun key") + return fmt.Errorf("failed to derive muun key: %w", err) } muunSignature, err := c.signature(index, tx, derivedUserKey.PublicKey(), derivedMuunKey.PublicKey(), derivedMuunKey) @@ -92,17 +94,17 @@ func (c *coinV2) signature(index int, tx *wire.MsgTx, userKey, muunKey *HDPublic redeemScript, err := createRedeemScriptV2(userKey, muunKey) if err != nil { - return nil, errors.Wrapf(err, "failed to build reedem script for signing") + return nil, fmt.Errorf("failed to build reedem script for signing: %w", err) } privKey, err := signingKey.key.ECPrivKey() if err != nil { - return nil, errors.Wrapf(err, "failed to produce EC priv key for signing") + return nil, fmt.Errorf("failed to produce EC priv key for signing: %w", err) } sig, err := txscript.RawTxInSignature(tx, index, redeemScript, txscript.SigHashAll, privKey) if err != nil { - return nil, errors.Wrapf(err, "failed to sign V2 output") + return nil, fmt.Errorf("failed to sign V2 output: %w", err) } return sig, nil diff --git a/vendor/github.com/muun/libwallet/V3.go b/vendor/github.com/muun/libwallet/V3.go index cbbffdd..9ce9526 100644 --- a/vendor/github.com/muun/libwallet/V3.go +++ b/vendor/github.com/muun/libwallet/V3.go @@ -1,11 +1,12 @@ package libwallet import ( + "errors" + "fmt" + "github.com/btcsuite/btcutil" "github.com/muun/libwallet/addresses" - "github.com/pkg/errors" - "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/wire" ) @@ -26,16 +27,16 @@ func (c *coinV3) SignInput(index int, tx *wire.MsgTx, userKey *HDPrivateKey, muu userKey, err := userKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive user key") + return fmt.Errorf("failed to derive user key: %w", err) } muunKey, err = muunKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive muun key") + return fmt.Errorf("failed to derive muun key: %w", err) } if len(c.MuunSignature) == 0 { - return errors.Errorf("muun signature must be present") + return errors.New("muun signature must be present") } witnessScript, err := createWitnessScriptV3(userKey.PublicKey(), muunKey) @@ -60,12 +61,12 @@ func (c *coinV3) FullySignInput(index int, tx *wire.MsgTx, userKey, muunKey *HDP derivedUserKey, err := userKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive user key") + return fmt.Errorf("failed to derive user key: %w", err) } derivedMuunKey, err := muunKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive muun key") + return fmt.Errorf("failed to derive muun key: %w", err) } muunSignature, err := c.signature(index, tx, derivedUserKey.PublicKey(), derivedMuunKey.PublicKey(), derivedMuunKey) @@ -94,7 +95,7 @@ func (c *coinV3) signature(index int, tx *wire.MsgTx, userKey *HDPublicKey, muun redeemScript, err := createRedeemScriptV3(userKey, muunKey) if err != nil { - return nil, errors.Wrapf(err, "failed to build reedem script for signing") + return nil, fmt.Errorf("failed to build reedem script for signing: %w", err) } return signNonNativeSegwitInput( diff --git a/vendor/github.com/muun/libwallet/V4.go b/vendor/github.com/muun/libwallet/V4.go index 7deef29..af53326 100644 --- a/vendor/github.com/muun/libwallet/V4.go +++ b/vendor/github.com/muun/libwallet/V4.go @@ -1,11 +1,11 @@ package libwallet import ( + "fmt" + "github.com/btcsuite/btcutil" "github.com/muun/libwallet/addresses" - "github.com/pkg/errors" - "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/wire" ) @@ -27,16 +27,16 @@ func (c *coinV4) SignInput(index int, tx *wire.MsgTx, userKey *HDPrivateKey, muu userKey, err := userKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive user key") + return fmt.Errorf("failed to derive user key: %w", err) } muunKey, err = muunKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive muun key") + return fmt.Errorf("failed to derive muun key: %w", err) } if len(c.MuunSignature) == 0 { - return errors.Errorf("muun signature must be present") + return fmt.Errorf("muun signature must be present: %w", err) } witnessScript, err := createWitnessScriptV4(userKey.PublicKey(), muunKey) @@ -61,12 +61,12 @@ func (c *coinV4) FullySignInput(index int, tx *wire.MsgTx, userKey, muunKey *HDP derivedUserKey, err := userKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive user key") + return fmt.Errorf("failed to derive user key: %w", err) } derivedMuunKey, err := muunKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive muun key") + return fmt.Errorf("failed to derive muun key: %w", err) } muunSignature, err := c.signature(index, tx, derivedUserKey.PublicKey(), derivedMuunKey.PublicKey(), derivedMuunKey) diff --git a/vendor/github.com/muun/libwallet/address.go b/vendor/github.com/muun/libwallet/address.go index d4c3907..e23b261 100644 --- a/vendor/github.com/muun/libwallet/address.go +++ b/vendor/github.com/muun/libwallet/address.go @@ -1,6 +1,7 @@ package libwallet import ( + "fmt" "io/ioutil" "net/http" "net/url" @@ -8,10 +9,10 @@ import ( "strings" "github.com/muun/libwallet/addresses" + "github.com/muun/libwallet/errors" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcutil" - "github.com/pkg/errors" "google.golang.org/protobuf/proto" ) @@ -44,11 +45,11 @@ func GetPaymentURI(rawInput string, network *Network) (*MuunPaymentURI, error) { bitcoinUri, components := buildUriFromString(rawInput, bitcoinScheme) if components == nil { - return nil, errors.Errorf("failed to parse uri %v", rawInput) + return nil, errors.Errorf(ErrInvalidURI, "failed to parse uri %v", rawInput) } if components.Scheme != "bitcoin" { - return nil, errors.New("Invalid scheme") + return nil, errors.New(ErrInvalidURI, "Invalid scheme") } base58Address := components.Opaque @@ -61,7 +62,7 @@ func GetPaymentURI(rawInput string, network *Network) (*MuunPaymentURI, error) { queryValues, err := url.ParseQuery(components.RawQuery) if err != nil { - return nil, errors.Wrapf(err, "Couldnt parse query") + return nil, errors.Errorf(ErrInvalidURI, "Couldn't parse query: %v", err) } var label, message, amount string @@ -110,11 +111,11 @@ func GetPaymentURI(rawInput string, network *Network) (*MuunPaymentURI, error) { // Bech32 check validatedBase58Address, err := btcutil.DecodeAddress(base58Address, network.network) if err != nil { - return nil, err + return nil, fmt.Errorf("invalid address: %w", err) } if !validatedBase58Address.IsForNet(network.network) { - return nil, errors.Errorf("Network mismatch") + return nil, errors.New(ErrInvalidURI, "Network mismatch") } return &MuunPaymentURI{ @@ -131,7 +132,7 @@ func GetPaymentURI(rawInput string, network *Network) (*MuunPaymentURI, error) { func DoPaymentRequestCall(url string, network *Network) (*MuunPaymentURI, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { - return nil, errors.Wrapf(err, "Failed to create request to: %s", url) + return nil, fmt.Errorf("failed to create request to: %s", url) } req.Header.Set("Accept", "application/bitcoin-paymentrequest") @@ -139,35 +140,35 @@ func DoPaymentRequestCall(url string, network *Network) (*MuunPaymentURI, error) client := &http.Client{} resp, err := client.Do(req) if err != nil { - return nil, errors.Wrapf(err, "Failed to make request to: %s", url) + return nil, errors.Errorf(ErrNetwork, "failed to make request to: %s", url) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - return nil, errors.Wrapf(err, "Failed to read body response") + return nil, errors.Errorf(ErrNetwork, "Failed to read body response: %w", err) } payReq := &PaymentRequest{} err = proto.Unmarshal(body, payReq) if err != nil { - return nil, errors.Wrapf(err, "Failed to Unmarshall paymentRequest") + return nil, fmt.Errorf("failed to unmarshal payment request: %w", err) } payDetails := &PaymentDetails{} err = proto.Unmarshal(payReq.SerializedPaymentDetails, payDetails) if err != nil { - return nil, errors.Wrapf(err, "Failed to Unmarshall paymentDetails") + return nil, fmt.Errorf("failed to unmarshall payment details: %w", err) } if len(payDetails.Outputs) == 0 { - return nil, errors.New("No outputs provided") + return nil, fmt.Errorf("no outputs provided") } address, err := getAddressFromScript(payDetails.Outputs[0].Script, network) if err != nil { - return nil, errors.Wrapf(err, "Failed to get address") + return nil, fmt.Errorf("failed to get address: %w", err) } return &MuunPaymentURI{ diff --git a/vendor/github.com/muun/libwallet/addresses/v2.go b/vendor/github.com/muun/libwallet/addresses/v2.go index 5cfbb8d..1f38356 100644 --- a/vendor/github.com/muun/libwallet/addresses/v2.go +++ b/vendor/github.com/muun/libwallet/addresses/v2.go @@ -1,6 +1,8 @@ package addresses import ( + "fmt" + "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcutil" @@ -12,12 +14,12 @@ func CreateAddressV2(userKey, muunKey *hdkeychain.ExtendedKey, path string, netw script, err := CreateRedeemScriptV2(userKey, muunKey, network) if err != nil { - return nil, errors.Wrapf(err, "failed to generate redeem script v2") + return nil, fmt.Errorf("failed to generate redeem script v2: %w", err) } address, err := btcutil.NewAddressScriptHash(script, network) if err != nil { - return nil, errors.Wrapf(err, "failed to generate multisig address") + return nil, fmt.Errorf("failed to generate multisig address: %w", err) } return &WalletAddress{ diff --git a/vendor/github.com/muun/libwallet/addresses/v3.go b/vendor/github.com/muun/libwallet/addresses/v3.go index f447c07..71bb8ea 100644 --- a/vendor/github.com/muun/libwallet/addresses/v3.go +++ b/vendor/github.com/muun/libwallet/addresses/v3.go @@ -2,13 +2,13 @@ package addresses import ( "crypto/sha256" + "fmt" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/hdkeychain" - "github.com/pkg/errors" ) func CreateAddressV3(userKey, muunKey *hdkeychain.ExtendedKey, path string, network *chaincfg.Params) (*WalletAddress, error) { @@ -33,7 +33,7 @@ func CreateAddressV3(userKey, muunKey *hdkeychain.ExtendedKey, path string, netw func CreateRedeemScriptV3(userKey, muunKey *hdkeychain.ExtendedKey, network *chaincfg.Params) ([]byte, error) { witnessScript, err := CreateWitnessScriptV3(userKey, muunKey, network) if err != nil { - return nil, errors.Wrapf(err, "failed to generate redeem script v3") + return nil, fmt.Errorf("failed to generate redeem script v3: %w", err) } return createNonNativeSegwitRedeemScript(witnessScript) diff --git a/vendor/github.com/muun/libwallet/addresses/v4.go b/vendor/github.com/muun/libwallet/addresses/v4.go index cb56037..b99dee6 100644 --- a/vendor/github.com/muun/libwallet/addresses/v4.go +++ b/vendor/github.com/muun/libwallet/addresses/v4.go @@ -2,11 +2,11 @@ package addresses import ( "crypto/sha256" + "fmt" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/hdkeychain" - "github.com/pkg/errors" ) // CreateAddressV4 returns a P2WSH WalletAddress from a user HD-pubkey and a Muun co-signing HD-pubkey. @@ -14,7 +14,7 @@ func CreateAddressV4(userKey, muunKey *hdkeychain.ExtendedKey, path string, netw witnessScript, err := CreateWitnessScriptV4(userKey, muunKey, network) if err != nil { - return nil, errors.Wrapf(err, "failed to generate witness script v4") + return nil, fmt.Errorf("failed to generate witness script v4: %w", err) } witnessScript256 := sha256.Sum256(witnessScript) diff --git a/vendor/github.com/muun/libwallet/aescbc/aescbc.go b/vendor/github.com/muun/libwallet/aescbc/aescbc.go index 1c4ddc3..a563d98 100644 --- a/vendor/github.com/muun/libwallet/aescbc/aescbc.go +++ b/vendor/github.com/muun/libwallet/aescbc/aescbc.go @@ -4,8 +4,7 @@ import ( "bytes" "crypto/aes" "crypto/cipher" - - "github.com/pkg/errors" + "errors" ) const KeySize = 32 diff --git a/vendor/github.com/muun/libwallet/challenge_keys.go b/vendor/github.com/muun/libwallet/challenge_keys.go index cacfa13..0f8a6de 100644 --- a/vendor/github.com/muun/libwallet/challenge_keys.go +++ b/vendor/github.com/muun/libwallet/challenge_keys.go @@ -5,16 +5,33 @@ import ( "crypto/sha256" "encoding/binary" "encoding/hex" + "errors" + "fmt" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcutil/base58" - "github.com/pkg/errors" +) + +const ( + // EncodedKeyLength is the size of a modern encoded key, as exported by the clients. + EncodedKeyLength = 147 + + // EncodedKeyLengthLegacy is the size of a legacy key, when salt resided only in the 2nd key. + EncodedKeyLengthLegacy = 136 ) type ChallengePrivateKey struct { key *btcec.PrivateKey } +type encryptedPrivateKey struct { + Version uint8 + Birthday uint16 + EphPublicKey []byte // 33-byte compressed public-key + CipherText []byte // 64-byte encrypted text + Salt []byte // (optional) 8-byte salt +} + type DecryptedPrivateKey struct { Key *HDPrivateKey Birthday int @@ -37,7 +54,7 @@ func (k *ChallengePrivateKey) SignSha(payload []byte) ([]byte, error) { sig, err := k.key.Sign(hash[:]) if err != nil { - return nil, errors.Wrapf(err, "failed to sign payload") + return nil, fmt.Errorf("failed to sign payload: %w", err) } return sig.Serialize(), nil @@ -53,43 +70,12 @@ func (k *ChallengePrivateKey) PubKey() *ChallengePublicKey { } func (k *ChallengePrivateKey) DecryptKey(encryptedKey string, network *Network) (*DecryptedPrivateKey, error) { - - reader := bytes.NewReader(base58.Decode(encryptedKey)) - version, err := reader.ReadByte() + decoded, err := decodeEncryptedPrivateKey(encryptedKey) if err != nil { - return nil, errors.Wrapf(err, "decrypting key") - } - if version != 2 { - return nil, errors.Errorf("decrypting key: found key version %v, expected 2", version) + return nil, err } - birthdayBytes := make([]byte, 2) - rawPubEph := make([]byte, serializedPublicKeyLength) - ciphertext := make([]byte, 64) - recoveryCodeSalt := make([]byte, 8) - - n, err := reader.Read(birthdayBytes) - if err != nil || n != 2 { - return nil, errors.Errorf("decrypting key: failed to read birthday") - } - birthday := binary.BigEndian.Uint16(birthdayBytes) - - n, err = reader.Read(rawPubEph) - if err != nil || n != serializedPublicKeyLength { - return nil, errors.Errorf("decrypting key: failed to read pubeph") - } - - n, err = reader.Read(ciphertext) - if err != nil || n != 64 { - return nil, errors.Errorf("decrypting key: failed to read ciphertext") - } - - n, err = reader.Read(recoveryCodeSalt) - if err != nil || n != 8 { - return nil, errors.Errorf("decrypting key: failed to read recoveryCodeSalt") - } - - plaintext, err := decryptWithPrivKey(k.key, rawPubEph, ciphertext) + plaintext, err := decryptWithPrivKey(k.key, decoded.EphPublicKey, decoded.CipherText) if err != nil { return nil, err } @@ -99,11 +85,68 @@ func (k *ChallengePrivateKey) DecryptKey(encryptedKey string, network *Network) privKey, err := NewHDPrivateKeyFromBytes(rawPrivKey, rawChainCode, network) if err != nil { - return nil, errors.Wrapf(err, "decrypting key: failed to parse key") + return nil, fmt.Errorf("decrypting key: failed to parse key: %w", err) } return &DecryptedPrivateKey{ privKey, - int(birthday), + int(decoded.Birthday), }, nil } + +func decodeEncryptedPrivateKey(encodedKey string) (*encryptedPrivateKey, error) { + reader := bytes.NewReader(base58.Decode(encodedKey)) + version, err := reader.ReadByte() + if err != nil { + return nil, fmt.Errorf("decrypting key: %w", err) + } + if version != 2 { + return nil, fmt.Errorf("decrypting key: found key version %v, expected 2", version) + } + + birthdayBytes := make([]byte, 2) + rawPubEph := make([]byte, serializedPublicKeyLength) + ciphertext := make([]byte, 64) + recoveryCodeSalt := make([]byte, 8) + + n, err := reader.Read(birthdayBytes) + if err != nil || n != 2 { + return nil, errors.New("decrypting key: failed to read birthday") + } + birthday := binary.BigEndian.Uint16(birthdayBytes) + + n, err = reader.Read(rawPubEph) + if err != nil || n != serializedPublicKeyLength { + return nil, errors.New("decrypting key: failed to read pubeph") + } + + n, err = reader.Read(ciphertext) + if err != nil || n != 64 { + return nil, errors.New("decrypting key: failed to read ciphertext") + } + + // NOTE: + // The very, very old format for encrypted keys didn't contain the encryption salt in the first + // of the two keys. This is a valid scenario, and a zero-filled salt can be returned. + if shouldHaveSalt(encodedKey) { + n, err = reader.Read(recoveryCodeSalt) + + if err != nil || n != 8 { + return nil, errors.New("decrypting key: failed to read recoveryCodeSalt") + } + } + + result := &encryptedPrivateKey{ + Version: version, + Birthday: birthday, + EphPublicKey: rawPubEph, + CipherText: ciphertext, + Salt: recoveryCodeSalt, + } + + return result, nil +} + +func shouldHaveSalt(encodedKey string) bool { + return len(encodedKey) > EncodedKeyLengthLegacy // not military-grade logic, but works for now +} diff --git a/vendor/github.com/muun/libwallet/challenge_public_key.go b/vendor/github.com/muun/libwallet/challenge_public_key.go index 545ac14..1effdf8 100644 --- a/vendor/github.com/muun/libwallet/challenge_public_key.go +++ b/vendor/github.com/muun/libwallet/challenge_public_key.go @@ -3,10 +3,10 @@ package libwallet import ( "bytes" "encoding/binary" + "fmt" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcutil/base58" - "github.com/pkg/errors" ) type ChallengePublicKey struct { @@ -37,7 +37,7 @@ func (k *ChallengePublicKey) EncryptKey(privKey *HDPrivateKey, recoveryCodeSalt plaintext = append(plaintext, rawHDKey[privKeyStart:privKeyStart+privKeyLength]...) plaintext = append(plaintext, rawHDKey[chainCodeStart:chainCodeStart+chainCodeLength]...) if len(plaintext) != 64 { - return "", errors.Errorf("failed to encrypt key: expected payload of 64 bytes, found %v", len(plaintext)) + return "", fmt.Errorf("failed to encrypt key: expected payload of 64 bytes, found %v", len(plaintext)) } pubEph, ciphertext, err := encryptWithPubKey(k.pubKey, plaintext) diff --git a/vendor/github.com/muun/libwallet/emergency_kit.go b/vendor/github.com/muun/libwallet/emergency_kit.go index bf9c212..0fc5e4e 100644 --- a/vendor/github.com/muun/libwallet/emergency_kit.go +++ b/vendor/github.com/muun/libwallet/emergency_kit.go @@ -1,32 +1,137 @@ package libwallet import ( + "encoding/hex" + "encoding/json" + "fmt" + "github.com/muun/libwallet/emergencykit" ) // EKInput input struct to fill the PDF type EKInput struct { FirstEncryptedKey string + FirstFingerprint string SecondEncryptedKey string + SecondFingerprint string } // EKOutput with the html as string and the verification code type EKOutput struct { HTML string VerificationCode string + Metadata string } -// GenerateEmergencyKitHTML returns the translated html as a string along with the verification code +// GenerateEmergencyKitHTML returns the translated html as a string along with the verification +// code and the kit metadata, represented in an opaque string. +// After calling this method, clients should use their Chromium/WebKit implementations to render +// the HTML into a PDF (better done there), and then come back to call `AddEmergencyKitMetadata` +// and produce the final PDF (better done here). func GenerateEmergencyKitHTML(ekParams *EKInput, language string) (*EKOutput, error) { - out, err := emergencykit.GenerateHTML(&emergencykit.Input{ + moduleInput := &emergencykit.Input{ FirstEncryptedKey: ekParams.FirstEncryptedKey, + FirstFingerprint: ekParams.FirstFingerprint, SecondEncryptedKey: ekParams.SecondEncryptedKey, - }, language) - if err != nil { - return nil, err + SecondFingerprint: ekParams.SecondFingerprint, + } + + // Create the HTML and the verification code: + htmlWithCode, err := emergencykit.GenerateHTML(moduleInput, language) + if err != nil { + return nil, fmt.Errorf("GenerateEkHtml failed to render: %w", err) + } + + // Create and serialize the metadata: + metadata, err := createEmergencyKitMetadata(ekParams) + if err != nil { + return nil, fmt.Errorf("GenerateEkHtml failed to create metadata: %w", err) + } + + metadataBytes, err := json.Marshal(&metadata) + if err != nil { + return nil, fmt.Errorf("GenerateEkHtml failed to marshal %s: %w", string(metadataBytes), err) + } + + output := &EKOutput{ + HTML: htmlWithCode.HTML, + VerificationCode: htmlWithCode.VerificationCode, + Metadata: string(metadataBytes), + } + + return output, nil +} + +// AddEmergencyKitMetadata produces a copy of the PDF file at `srcFile` with embedded metadata, +// writing it into `dstFile`. The provided metadata must be the same opaque string produced by +// `GenerateEmergencyKitHTML`. +func AddEmergencyKitMetadata(metadataText string, srcFile string, dstFile string) error { + // Initialize the MetadataWriter: + metadataWriter := &emergencykit.MetadataWriter{ + SrcFile: srcFile, + DstFile: dstFile, + } + + // Deserialize the metadata: + var metadata emergencykit.Metadata + + err := json.Unmarshal([]byte(metadataText), &metadata) + if err != nil { + return fmt.Errorf("AddEkMetadata failed to unmarshal: %w", err) + } + + err = metadataWriter.WriteMetadata(&metadata) + if err != nil { + return fmt.Errorf("AddEkMetadata failed to write metadata: %w", err) + } + + return nil +} + +func createEmergencyKitMetadata(ekParams *EKInput) (*emergencykit.Metadata, error) { + // NOTE: + // This method would be more naturally placed in the `emergencykit` module, but given the current + // project structure (heavily determined by `gomobile` and the need for top-level bindings) and + // the use of `decodeEncryptedPrivateKey` this isn't possible. Instead, we peek through the layer + // boundary to craft the object here. + + // Decode both keys, to extract their inner properties: + firstKey, err := decodeEncryptedPrivateKey(ekParams.FirstEncryptedKey) + if err != nil { + return nil, fmt.Errorf("createEkMetadata failed to decode first key: %w", err) + } + + secondKey, err := decodeEncryptedPrivateKey(ekParams.SecondEncryptedKey) + if err != nil { + return nil, fmt.Errorf("createEkMetadata failed to decode second key: %w", err) + } + + // Obtain the list of checksumed output descriptors: + descriptors := emergencykit.GetDescriptors(&emergencykit.DescriptorsData{ + FirstFingerprint: ekParams.FirstFingerprint, + SecondFingerprint: ekParams.SecondFingerprint, + }) + + // Create the keys for the key array: + keys := []*emergencykit.MetadataKey{ + createEmergencyKitMetadataKey(firstKey), + createEmergencyKitMetadataKey(secondKey), + } + + metadata := &emergencykit.Metadata{ + Version: 2, + BirthdayBlock: int(secondKey.Birthday), + EncryptedKeys: keys, + OutputDescriptors: descriptors, + } + + return metadata, nil +} + +func createEmergencyKitMetadataKey(key *encryptedPrivateKey) *emergencykit.MetadataKey { + return &emergencykit.MetadataKey{ + DhPubKey: hex.EncodeToString(key.EphPublicKey), + EncryptedPrivKey: hex.EncodeToString(key.CipherText), + Salt: hex.EncodeToString(key.Salt), } - return &EKOutput{ - HTML: out.HTML, - VerificationCode: out.VerificationCode, - }, nil } diff --git a/vendor/github.com/muun/libwallet/emergencykit/content.go b/vendor/github.com/muun/libwallet/emergencykit/content.go index 7c8cb1e..282c81d 100644 --- a/vendor/github.com/muun/libwallet/emergencykit/content.go +++ b/vendor/github.com/muun/libwallet/emergencykit/content.go @@ -2,7 +2,6 @@ package emergencykit type pageData struct { Css string - Logo string Content string } @@ -11,17 +10,11 @@ type contentData struct { SecondEncryptedKey string VerificationCode string CurrentDate string + Descriptors string + IconHelp string + IconPadlock string } -const logo = ` - - ` - const page = ` @@ -36,7 +29,6 @@ const page = ` - {{.Logo}} {{.Content}} @@ -44,225 +36,322 @@ const page = ` const contentEN = `
-
-

Emergency Kit

- Created on {{.CurrentDate}} -
- -
-

Verification code

- {{.VerificationCode}} -
+

Emergency Kit

+

Verification #{{.VerificationCode}}

-
-

About this document

- -

Here you'll find the encrypted information you need to transfer your money out of your Muun wallet without - requiring collaboration from anyone, including Muun's own software and servers.

- -

This includes all your private keys (securely encrypted with your Recovery Code) and some additional data related - to your wallet.

- -

With this document and your recovery code at hand, you have complete ownership of your money. Nobody else has - all the pieces. This is why Bitcoin was created: to give people full control of the money they rightly own.

-
- -
-

Recovering your money

- -

To move forward with the transfer of funds, we recommend using our - open-source Recovery Tool. It's available for the whole world to - download and examine, and it will always be.

- -

We created it to assist you with the process, but nothing stops you from doing it manually if you're so - inclined.

- -

Go to github.com/muun/recovery and follow the instructions to easily transfer your money to a Bitcoin - address of your choosing.

-
- -
-

Recovery information

- -

This is what you'll need for the transfer, plus your recovery code. If these random-seeming codes look daunting, - don't worry: the recovery tool will take care of everything.

-
- -
-

First Encrypted Private Key

-
{{.FirstEncryptedKey}}
- -

Second Encrypted Private Key

-
{{.SecondEncryptedKey}}
- -

Output descriptors

-
- sh(wsh(multi(2, first key/1'/1'/0/*, second key/1'/1'/0/*)))
- sh(wsh(multi(2, first key/1'/1'/1/*, second key/1'/1'/1/*)))
- sh(wsh(multi(2, first key/1'/1'/2/*/*, second key/1'/1'/2/*/*)))
- wsh(multi(2, first key/1'/1'/0/*, second key/1'/1'/0/*))
- wsh(multi(2, first key/1'/1'/1/*, second key/1'/1'/1/*))
- wsh(multi(2, first key/1'/1'/2/*/*, second key/1'/1'/2/*/*)) +
+
+ {{.IconPadlock}} +
+

Encrypted backup

+

It can only be decrypted using your Recovery Code.

+
+ +
+ +
+

First key

+

{{.FirstEncryptedKey}}

+
+ +
+

Second key

+

{{.SecondEncryptedKey}}

+
+ +
+ Created on {{.CurrentDate}} +
+
+
+ +
+

Instructions

+

This emergency procedure will help you recover your funds if you are unable to use Muun on your phone.

+ +
+
+
1
+
+
+

Find your Recovery Code

+

You wrote this code on paper before creating your Emergency Kit. You’ll need it later.

+
+
+ +
+
+
2
+
+
+

Download the Recovery Tool

+

Go to github.com/muun/recovery and download the tool on your computer.

+
+
+ +
+
+
3
+
+
+

Recover your funds

+

Run the Recovery Tool and follow the steps. It will safely transfer your funds to a Bitcoin address that you + choose.

+
+
-
-

Some questions you might have

- -

Can I print this document?

- -

You can, but we recommend storing it online in a service such as Google Drive, iCloud, OneDrive or Dropbox. - These providers have earned their users' trust by being always available and safeguarding data with strong - security practices. They are also free.

- -

If you decide to print it, be sure to keep it safely away from where you store your recovery code. Remember: - a person with both pieces can take control of your funds.

- -

What if I lose my emergency kit?

- -

Don't panic. Your money is not lost. It's all there, in the Bitcoin blockchain, waiting for you. Use our Android - or iOS applications and go to the Security Center to create a new kit.

- -

What if somebody sees this document?

+
+{{.IconHelp}} +
+

Need help?

- As long as you keep your recovery code hidden, this document is harmless. All the data it contains is safely - encrypted, and only your recovery code can decrypt it to a usable form.

- -

Still, we recommend that you keep it where only you can see it. If you really fear losing it or want to share it - for some other reason, only do so with people that enjoy your absolute trust.

- -

Why don't I have a mnemonic phrase?

- -

If you've been involved with Bitcoin for some time, you've probably seen mnemonics and been told to rely on them. - As of this writing, many wallets still use the technique.

- -

There's nothing inherently wrong with mnemonics, but they have been rendered obsolete. The twelve words are - simply not enough to encode all the information a modern Bitcoin wallet requires to operate, and the problem will - only get worse as technology advances. Already there are improvements taking shape that would make mnemonic - recovery not only harder, but impossible.

- -

For this reason, we decided to guarantee full ownership using a safer, more flexible and future-proof technique. - This way, we'll be able to keep up with technological improvements and continue to provide - state-of-the-art software.

- -

I have other questions

- -

We'll be glad to answer them. Contact us at support@muun.com - to let us know.

+ Contact us at support@muun.com. We’re always there to help. +

+
- - ` +
+

Advanced information

+ +

Output descriptors

+

These descriptors, combined with your keys, specify how to locate your wallet’s funds on the Bitcoin blockchain.

+ + {{ if .Descriptors }} + {{.Descriptors}} + {{ else }} +
    + +
  • sh(wsh(multi(2, first key/1'/1'/0/*, second key/1'/1'/0/*)))
  • +
  • sh(wsh(multi(2, first key/1'/1'/1/*, second key/1'/1'/1/*)))
  • +
  • sh(wsh(multi(2, first key/1'/1'/2/*/*, second key/1'/1'/2/*/*)))
  • +
  • wsh(multi(2, first key/1'/1'/0/*, second key/1'/1'/0/*))
  • +
  • wsh(multi(2, first key/1'/1'/1/*, second key/1'/1'/1/*))
  • +
  • wsh(multi(2, first key/1'/1'/2]/*/*, second key/1'/1'/2/*/*))
  • +
+ {{ end }} + +

+ Output descriptors are part of a developing standard for Recovery that Muun intends to support and is helping grow. + Since the standard is in a very early stage, the list above includes some non-standard elements. +

+ +

+ When descriptors reach a more mature stage, you’ll be able to take your funds from one wallet to another with + complete independence. Muun believes this freedom is at the core of Bitcoin’s promise, and is working towards + that goal. +

+
+` const contentES = `
-
-

Kit de Emergencia

- Creado el {{.CurrentDate}} -
- -
-

Código de Verificación

- {{.VerificationCode}} -
+

Kit de Emergencia

+

Verificación #{{.VerificationCode}}

-
-

Sobre este documento

- -

Aquí encontrarás la información encriptada que necesitas para transferir tu dinero fuera de tu billetera Muun - sin requerir colaboración de nadie, incluso del software y los servicios de Muun.

- -

Ésto incluye todas tus claves privadas (encriptadas de forma segura con tu Recovery Code) y algo de información - adicional relacionada a tu billetera.

- -

Con éste documento y to Código de Recuperación a mano, tienes posesión total de tu dinero. Nadie más tiene - todas las piezas. Bitcoin fue creado para esto: darle a la gente control total sobre el dinero que les pertenece.

-
- -
-

Recuperando tu dinero

- -

Para proceder con la transferencia de tus fondos, recomendamos usar nuestra - Herramienta de Recuperación de código abierto. Está disponible para que - todo el mundo la descargue y la examine, y siempre lo estará.

- -

La creamos para asistirte en el proceso, pero nada te impide hacerlo manualmente si prefieres.

- -

Entra en github.com/muun/recovery y sigue las instrucciones para transferir tu dinero a una - dirección de Bitcoin que elijas.

-
- -
-

Información de recuperación

- -

Ésto es lo que necesitas para la transferencia, además de tu Código de Recuperación. Si éstos códigos te parecen - confusos, no te precupes: la Herramienta de Recuperación se hará cargo - de todo

-
- -
-

Primera Clave Privada Encriptada

-
{{.FirstEncryptedKey}}
- -

Segunda Clave Privada Encriptada

-
{{.SecondEncryptedKey}}
- -

Descriptores de outputs

-
- sh(wsh(multi(2, primera clave/1'/1'/0/*, segunda clave/1'/1'/0/*)))
- sh(wsh(multi(2, primera clave/1'/1'/1/*, segunda clave/1'/1'/1/*)))
- sh(wsh(multi(2, primera clave/1'/1'/2/*/*, segunda clave/1'/1'/2/*/*)))
- wsh(multi(2, primera clave/1'/1'/0/*, segunda clave/1'/1'/0/*))
- wsh(multi(2, primera clave/1'/1'/1/*, segunda clave/1'/1'/1/*))
- wsh(multi(2, primera clave/1'/1'/2/*/*, segunda clave/1'/1'/2/*/*)) +
+
+ {{.IconPadlock}} +
+

Respaldo encriptado

+

Sólo puede ser desencriptado con tu Código de Recuperación.

+
+ +
+ +
+

Primera clave

+

{{.FirstEncryptedKey}}

+
+ +
+

Segunda clave

+

{{.SecondEncryptedKey}}

+
+ +
+ Creado el {{.CurrentDate}} +
+
+
+ +
+

Instrucciones

+

Éste procedimiento de emergencia te ayudará a recuperar tus fondos si no puedes usar Muun en tu teléfono.

+ +
+
+
1
+
+
+

Encuentra tu Código de Recuperación

+

Lo escribiste en papel antes de crear tu Kit de Emergencia. Lo necesitarás después.

+
+
+ +
+
+
2
+
+
+

Descarga la Herramienta de Recuperación

+

Ingresa en github.com/muun/recovery y descarga la herramienta en tu computadora..

+
+
+ +
+
+
3
+
+
+

Recupera tus fondos

+

Ejecuta la Herramienta de Recuperación y sigue los pasos. Transferirá tus fondos a una dirección de Bitcoin que elijas.

+
+
-
-

Algunas preguntas que puedes tener

- -

¿Puedo imprimir éste documento?

- -

Puedes, pero recomendamos almacenarlo online, en algún servicio como Google Drive, iCloud, OneDrive o Dropbox. - Éstos proveedores se han ganado la confianza de sus usuarios por estar siempre disponibles y custodiar su información - con fuertes prácticas de seguridad. También son gratuitos.

- -

Si decides imprimirlos, asegúrate de guardarlos en algún lugar seguro y lejos de tu Código de Recuperación. Recuerda: - una persona con ambas piezas puede tomar control de tus fondos.

- -

¿Qué pasa si pierdo mi Kit de Emergencia?

- -

No te preocupes. Tu dinero no está perdido. Está todo ahí, en la blockchain de Bitcoin, esperándote. Usa nuestras - aplicaciones de Android o iOS y crea un nuevo Kit en el Centro de Seguridad.

- -

¿Qué pasa si alguien ve éste documento?

- -

Mientras tengas tu Código de Recuperación escondido, éste documento es inofensivo. Todo la información que contiene - está encriptada de forma segura, y sólo tu Código de Recuperación puede desencriptarla para poder usarla.

- -

Aún así, recomendamos que lo guardes donde sólo tú puedes verlo. Si realmente te preocupa perderlo o quieres - compartirlo con alguien por otra razón, sólo hazlo con gente de plena confianza.

- -

¿Por qué no tengo mi mnemonic?

- -

Si estás familiarizado con Bitcoin, probablemente hayas visto las mnemonics y aprendido a confiar en ellas. - Al día de hoy, muchas billeteras utilizan esa técnica.

- -

Las mnemonics no tienen ningún problema intrínseco, pero han quedado obsoletas. Las doce palabras no son suficientes para codificar - toda la información que una billetera moderna de Bitcoin necesita para funcionar, y el problema sólo se pondrá peor - a medida que la tecnología avance. Ya hay mejoras encaminadas que harían la recuperación con mnemonics no sólo - difícil, sino imposible.

- -

Por eso decidimos garantizar la posesión completa con un método más seguro, flexible y capaz de evolucionar. - De ésta manera, podremos seguir mejorando nuestra tecnología y continuar modernizando nuestro software.

- -

Tengo otras preguntas

- -

Siempre estamos disponibles para contestarlas. Contáctanos a support@muun.com - y te ayudaremos.

+
+{{.IconHelp}} +
+

¿Necesitas ayuda?

+

+ Contáctanos en support@muun.com. Siempre estamos disponibles para ayudar. +

+
- - ` +
+

Información Avanzada

+ +

Output descriptors

+

Estos descriptors, combinados con tus claves, indican cómo encontrar los fondos de tu billetera en la blockchain de Bitcoin.

+ + {{ if .Descriptors }} + {{.Descriptors}} + {{ else }} +
    + +
  • sh(wsh(multi(2, primera clave/1'/1'/0/*, segunda clave/1'/1'/0/*)))
  • +
  • sh(wsh(multi(2, primera clave/1'/1'/1/*, segunda clave/1'/1'/1/*)))
  • +
  • sh(wsh(multi(2, primera clave/1'/1'/2/*/*, segunda clave/1'/1'/2/*/*)))
  • +
  • wsh(multi(2, primera clave/1'/1'/0/*, segunda clave/1'/1'/0/*))
  • +
  • wsh(multi(2, primera clave/1'/1'/1/*, segunda clave/1'/1'/1/*))
  • +
  • wsh(multi(2, primera clave/1'/1'/2]/*/*, segunda clave/1'/1'/2/*/*))
  • +
+ {{ end }} + +

+Los output descriptors son parte de un estándar de recuperación actualmente en desarrollo. Muun tiene la intención +de soportar este estándar y apoyar su crecimiento. Dado que se encuentra en una etapa muy temprana, la siguiente lista +incluye algunos elementos que aún no están estandarizados. +

+ +

+Cuando los descriptors lleguen a una etapa más madura, podrás llevar tus fondos de una billetera a la otra con completa +independencia. Muun cree que ésta libertad es central a la promesa de Bitcoin, y está trabajando para que eso suceda. +

+
+` + +const iconHelp = ` + + + + + + + + + + + + + + + + + + + + + + + +` + +const iconPadlock = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +` diff --git a/vendor/github.com/muun/libwallet/emergencykit/css.go b/vendor/github.com/muun/libwallet/emergencykit/css.go index 13d9f3e..ea1f4cc 100644 --- a/vendor/github.com/muun/libwallet/emergencykit/css.go +++ b/vendor/github.com/muun/libwallet/emergencykit/css.go @@ -1,154 +1,226 @@ package emergencykit +// NOTE: +// To view this file comfortably, disable line-wrapping in your editor. + const css = ` -@font-face { - font-family: Roboto; - font-weight: 400; - src: url(data:font/ttf;base64,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MDH//wANAAAEHAYeAiYB0wAAAQYAnj0eABQAsABFWLAILxuxCBw+WbENBPQwMf//AA0AAAQcBeMCJgHTAAABBgBqbR4AFwCwAEVYsAgvG7EIHD5ZsRAC9LAZ0DAxAP//AEcAAAPgBh4CJgHSAAABBwB1ATMAHgAUALAARViwCC8bsQgcPlmxDAb0MDH//wBHAAAD4AXgAiYB0gAAAQcAogEaAB4AFACwAEVYsAcvG7EHHD5ZsREC9DAx//8ARwAAA+AGHgImAdIAAAEGAJ9SHwAUALAARViwBy8bsQccPlmxDwb0MDH//wAcAAAFHQY/AiYAJQAAAAYArgQA////KQAABEYGPwImACkAAAAHAK7+cgAA////NwAABQgGQQImACwAAAAHAK7+gAAC////PQAAAXcGQAImAC0AAAAHAK7+hgAB////5v/sBR0GPwAmADMUAAAHAK7/LwAA////FAAABR8GPwAmAD1kAAAHAK7+XQAA////6QAABN8GPwAmALoUAAAHAK7/MgAA////m//0Aq0GdAImAMMAAAEHAK//Kv/sAB0AsABFWLAMLxuxDBo+WbEYAfSwD9CwGBCwIdAwMQD//wAcAAAFHQWwAgYAJQAA//8AqQAABIgFsAIGACYAAP//AKkAAARGBbACBgApAAD//wBWAAAEegWwAgYAPgAA//8AqQAABQgFsAIGACwAAP//ALcAAAF3BbACBgAtAAD//wCpAAAFBQWwAgYALwAA//8AqQAABlIFsAIGADEAAP//AKkAAAUIBbACBgAyAAD//wB2/+wFCQXEAgYAMwAA//8AqQAABMAFsAIGADQAAP//ADEAAASXBbACBgA4AAD//wAPAAAEuwWwAgYAPQAA//8AOQAABM4FsAIGADwAAP///9UAAAJeBwcCJgAtAAABBwBq/3ABQgAXALAARViwAi8bsQIePlmxCwT0sBTQMDEA//8ADwAABLsG+wImAD0AAAEHAGoAwgE2ABcAsABFWLAILxuxCB4+WbEQBPSwGdAwMQD//wBk/+sEdwY6AiYAuwAAAQcArgF1//sAFACwAEVYsBMvG7ETGj5ZsSQB9DAx//8AY//sA+wGOQImAL8AAAEHAK4BK//6ABQAsABFWLAVLxuxFRo+WbEoAfQwMf//AJH+YQPwBjoCJgDBAAABBwCuAUb/+wAUALAARViw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BkkAWwOTAJMDwQBmBG4AfwZKAFoDqgCOAv0AggRGAGEC7wBCAu8APgKCAHsEiACaA+kAQwIWAJMB+wB0Au8AegOjAHoDwABmBdwAVQY1AFAGOQBvA8kARAd6//IERABZBYAAdgS6AKYEwgCLBsEATgSwAH4EkQBHBIgAWwScAJUExwBfBZoAHQH6AJsEcwCaBE8AIgIpACIFiwCiBIgAkQehAGgHRABhAfwAoAWHAF0Cuf/kBX4AZQSSAFsFkACMBPMAiAID/7QENwBiA8QAqQONAI0DqwCOA2oAgQHxAI0CrQB5AioAMgPGAHsC/ABeAloAfgAA/KcAAP1vAAD8iwAA/V4AAPwnAAD9OAINALcECwBxAhcAkwRzALEFpAAfBXEAZwU+ADIEkQB4BbUAsgSRAEUFuwBNBYkAWgVSAHEEhQBkBL0AoAQCAC4EiABgBFAAYwQlAG0EiACRBI4AegKXAMMEbgAlA+wAZQTEACkEiACRBE0AZQSIAGAELABRBF0AjwWjAFcFmgBfBpcAegShAHkEQv/aBkgASgX/ACoFZAB7CJEAMQikALEGggA+BbQAsAULAKIGBAAyB0MAGwS/AFAFtACxBakALwUHAE0GLABTBdkArwV6AJYHhwCwB8AAsAYSABAG6wCyBQUAowVkAJMHJwC3BRgAWQRsAGEEkgCdA1sAmgTUAC4GIAAVBBAAWASeAJwEUgCcBKAALAXvAJ0EnQCcBJ4AnAPYACgFzQBkBL0AnARZAGcGeACcBp4AkQT3AB4GNgCdBFgAnQRNAGQGhwCdBGQALwRo/+gETQBnBskAJwbkAJwEif/9BJ4AnAcIAJwGKwCBBFb/3AcrALcF+ACZBNIAKARGAA8HCwDJBgsAvAbRAJMF4QCWCQQAtgfRAJsEIwBQA9sATAVxAGcEiwBbBQoAFgQDAC4FcQBnBIgAWwcBAJwGJAB+BwgAnAYrAIEFMgB1BEcAZAT9AHQAAPxnAAD8cQAA/WYAAP2kAAD6GwAA+iwGCQCxBO0AnARW/9wFGwCoBIkAjARjAKIDkACRBNsAsQQFAJEHogAbBmEAFQWaALIEuACcBQkAowR+AJoGjABEBYMAPgX/AKkE2QCcB88AqAW0AJEIMQCwBvQAkQXuAHEE0wBtBRgAOQQqACkHLAA0BVwAHwW8AJYElgBnBW8AlgRqAIMFbwCJBi8APwS9/94FCQCjBFoAmgX+AC8E7wAsBbIAsQSIAJEGEgCpBOwAnAdPAKkGPgCdBYcAXQSoAGgEqABpBLcAOgOrADsFLgA5BEAAKQT2AFcGlABZBuQAZAZWADYFKwAxBEkAUgQHAHkHwQBEBnUAPwf7AKkGoQCQBPYAdgQdAGUFrQAjBSAARgVkAJYGAgAvBPIALAMgAG8EFAAACCkAAAQUAAAIKQAAArkAAAIKAAABXAAABH8AAAIwAAABogAAAQAAAADRAAAAAAAAAjQAJQI0ACUFQACiBj8AkAOlAA0BmQBgAZkAMAGXACQBmQBPAtQAaALbADwCwQAkBGkARgSPAFcCsgCKA8QAlAVaAJQBfgBSB6oARAJmAGwCZgBZA6MAOwLvADYDYAB6BKYAWwZVAB8GkACnCHYAqAXrAB8GKwCMBH4AXwXaAB8EIgAqBHQAIAVIAF0FTwAfBecAegPOAGgIOgCiBQEAZwUXAJgGJgBUBtcAZAbPAGMGagBZBI8AagWOAKkErwBFBJIAqATFAD8IOgBiAgz/sASCAGUEZACYBBEAPgQvAIUECAArAkwAtQKPAG4CAwBcBPMAPARuAB8EiwA8BtQAPAbUADwE7gA8BpsAXwAAAAAIMwBbCDUAXALvAEIC7wB6Au8AUAQPAFUEDwBgBA8AQgQOAHIEDwCABA8AMAQPAE4EDwBOBA8AmAQPAGMEIwBHBCsADQRUACYGFQAxBGcAFAR8AHQEJgAoBCAAQwRKAIoEuwBZBFwAigS7AGAE4wCKBgIAigO0AIoEVACKA88AKwHoAJcE4wCKBKwAYwPLAIoEIABDBDMAMAOhAA0DrwCKBGcAFAS7AGAEZwAUA4kAPgTOAIoD7wA/BWcAYAUXAGAE8gB1BXIAJgR8AGAHQQAnB08AigV0ACgEzQCKBFkAigUkAC4GCwAfBD8ARwTsAIoETgCLBMEAJwQfACIFKACKBGoAPQZRAIoGrACKBR0ACAXxAIoETgCKBHsASwZ2AIoEhwBQBBEACwZHAB8EeQCLBQkAiwU3ACMFwgBgBF8ADQSoACYGYQAmBGoAPQRqAIoFwwACBMoAXgQ/AEcEuwBgBDMAMAPjAEIIIgCKBKsAKALvAD4C7wA2Au8AWwLvAFYC7wA6Au8ATwLvAEkDlgCPArUAngPmAIoEOgAeBMMAZAVMALEFJACyBBMAkgU9ALIEDwCSBIAAigR8AGAEUACKBIUAEwH9AJ8DpACBAAD8pAPvAG4D8/9eBA4AaQP0AGkDrwCKA58AgQOeAIEC7wBQAu8ANgLvAFsC7wBWAu8AOgLvAE8C7wBJBYEAfgWuAH4FkwCyBeAAfgXjAH4D1QCgBIIAgwRYAA8EzwA+BGsAZQQuAEoDpACDAZEAZwakAGAEuQCCAfz/tgR/ADsEfwBzBH8AIwR/AHcEfwB2BH8ANwR/AH4EfwBfBH8AcAR/APQCBv+0AgT/tAH7AJsB+//6AfsAmwRQAIoFAAB4BCAAOwR9AIwEMgBcBJMAWwSMAFsEngBaBI0AjAScAFsEPQBdBH0AYAN5AFcE1gBnA7QAAAY5AAkD+ACKBLsAYATjADAE4wCKAfsAAAI1ACUFXQAHBV0ABwSG/+IExgAxAp3/9AU4ABwFOAAcBTgAHAU4ABwFOAAcBTgAHAU4ABwFNQB3BIwAqQSMAKkEjACpBIwAqQIt/+ACLQCwAi3/6QIt/9UFtACpBYAAdgWAAHYFgAB2BYAAdgWAAHYFMACMBTAAjAUwAIwFMACMBM4ADwRaAG0EWgBtBFoAbQRaAG0EWgBtBFoAbQRaAG0EMABcBD0AXQQ9AF0EPQBdBD0AXQH6/8YB+gCWAfr/zwH6/7sEagCMBJAAWwSQAFsEkABbBJAAWwSQAFsEaQCIBGkAiARpAIgEaQCIA8kAFgPJABYFOAAcBFoAbQU4ABwEWgBtBTgAHARaAG0FNQB3BDAAXAU1AHcEMABcBTUAdwQwAFwFNQB3BDAAXAU/AKkFGQBfBIwAqQQ9AF0EjACpBD0AXQSMAKkEPQBdBIwAqQQ9AF0EjACpBD0AXQVzAHoEfQBgBXMAegR9AGAFcwB6BH0AYAVzAHoEfQBgBbQAqQRoAIwCLf+3Afr/nQIt/8wB+v+yAi3/7AH6/9ICLQAYAfH/+wItAKkGlwC3A9oAjQRqADUCA/+0BQQAqQQOAI0ETgChAfEAkwROAKkB8QBXBE4AqQKHAJwETgCpAs0AnAW0AKkEagCMBbQAqQRqAIwFtACpBGoAjARq/7wFgAB2BJAAWwWAAHYEkABbBYAAdgSQAFsE7QCoArUAjATtAKgCtQBTBO0AqAK1AGMEvwBQBCAAXwS/AFAEIABfBL8AUAQgAF8EvwBQBCAAXwS/AFAEIABfBMYAMQKdAAkExgAxAp0ACQTGADECxQAJBTAAjARpAIgFMACMBGkAiAUwAIwEaQCIBTAAjARpAIgFMACMBGkAiAUwAIwEaQCIBxkAPQYDACsEzgAPA8kAFgTOAA8EygBWA/cAWATKAFYD9wBYBMoAVgP3AFgHev/yBsEATgWAAHYEiABbBID/vgSA/74EJgAoBIUAEwSFABMEhQATBIUAEwSFABMEhQATBIUAEwR8AGAD5gCKA+YAigPmAIoD5gCKAej/vgHoAI4B6P/HAej/swTjAIoEuwBgBLsAYAS7AGAEuwBgBLsAYAR8AHQEfAB0BHwAdAR8AHQEKwANBIUAEwSFABMEhQATBHwAYAR8AGAEfABgBHwAYASAAIoD5gCKA+YAigPmAIoD5gCKA+YAigSsAGMErABjBKwAYwSsAGME4wCKAej/lQHo/6oB6P/KAegABgHoAIgDzwArBFQAigO0AIIDtACKA7QAigO0AIoE4wCKBOMAigTjAIoEuwBgBLsAYAS7AGAESgCKBEoAigRKAIoEIABDBCAAQwQgAEMEIABDBCYAKAQmACgEJgAoBHwAdAR8AHQEfAB0BHwAdAR8AHQEfAB0BhUAMQQrAA0EKwANBCMARwQjAEcEIwBHBTgAHASM/ykFtP83Ai3/PQWU/+YFMv8UBWb/6QKX/5sFOAAcBPsAqQSMAKkEygBWBbQAqQItALcFBACpBvwAqQW0AKkFgAB2BQwAqQTGADEEzgAPBQQAOQIt/9UEzgAPBIUAZARQAGMEiACRApcAwwRdAI8EcwCaBJAAWwSIAJoD4AAhA/cAKQKX/+UEXQCPBJAAWwRdAI8GlwB6BIwAqQRzALEEvwBQAi0AtwIt/9UEagA1BSQAsgUEAKkFBwBNBTgAHAT7AKkEcwCxBIwAqQW0ALEG/ACpBbQAqQWAAHYFtQCyBQwAqQU1AHcExgAxBQQAOQRaAG0EPQBdBJ4AnASQAFsEfQCMBDAAXAPJABYD9wApBD0AXQNbAJoEIABfAfEAjQH6/7sB6f+/BFIAnAPJABYHGQA9BgMAKwcZAD0GAwArBxkAPQYDACsEzgAPA8kAFgFlAGcCjwCIBB4AoAID/7QBmQAwBvwAqQcDAIsFOAAcBFoAbQSMAKkFtACxBD0AXQSeAJwFiQBaBZoAXwUKABYEA//7CFkAWwlJAHYEvwBQBBAAWAU1AHcEMABcBM4ADwQCAC4CLQC3B0MAGwYgABUCLQC3BTgAHARaAG0FOAAcBFoAbQd6//IGwQBOBIwAqQQ9AF0FhwBdBDcAYgQ3AGIHQwAbBiAAFQS/AFAEEABYBbQAsQSeAJwFtACxBJ4AnAWAAHYEkABbBXEAZwSLAFsFcQBnBIsAWwVkAJMETQBkBQcATQPJABYFBwBNA8kAFgUHAE0DyQAWBXoAlgRZAGcG6wCyBjYAnQSDAF8FOAAcBFoAbQU4ABwEWgBtBTgAHARaAG0FOAAcBFr/ygU4ABwEWgBtBTgAHARaAG0FOAAcBFoAbQU4ABwEWgBtBTgAHARaAG0FOAAcBFoAbQU4ABwEWgBtBTgAHARaAG0EjACpBD0AXQSMAKkEPQBdBIwAqQQ9AF0EjACpBD0AXQSM//AEPf+6BIwAqQQ9AF0EjACpBD0AXQSMAKkEPQBdAi0AtwH6AJsCLQCjAfEAhQWAAHYEkABbBYAAdgSQAFsFgAB2BJAAWwWAAEcEkP/EBYAAdgSQAFsFgAB2BJAAWwWAAHYEkABbBX4AZQSSAFsFfgBlBJIAWwV+AGUEkgBbBX4AZQSSAFsFfgBlBJIAWwUwAIwEaQCIBTAAjARpAIgFkACMBPMAiAWQAIwE8wCIBZAAjATzAIgFkACMBPMAiAWQAIwE8wCIBM4ADwPJABYEzgAPA8kAFgTOAA8DyQAWBKEAXwTGADED2AAoBXoAlgRZAGcEcwCxA1sAmgYvAD8Evf/eBGgAjAUF/9QFBf/UBHMAAwNb//wFOP/3BCf/vwTOAA8EAgAuBQQAOQP3ACkEUABjBGwAEgY/AJAEfgBdBH4AXgR+ADUEfgCaBJIAmASmAIQEkgBkBKYAhwVzAHoEfQBgBbQAqQRqAIwFOAAcBFoAOQSMAF8EPQApAi3/CgH6/vAFgAB2BJAAMwTtAFUCtf+LBTAAjARpACsEpv7WBPsAqQR9AIwFPwCpBIMAXwU/AKkEgwBfBbQAqQRoAIwFBACpBA4AjQUEAKkEDgCNBE4AqQHxAIYG/ACpBwMAiwW0AKkEagCMBYAAdgUMAKkEfQCMBO0AqAK1AIIEvwBQBCAAXwTGADECnQAJBTAAjAUXABwD4AAhBRcAHAPgACEHGQA9BgMAKwTKAFYD9wBYBcb+MgSFABMEIv9jBR//gAIk/4QExf/VBGf/GwT8/+4EhQATBFAAigPmAIoEIwBHBOMAigHoAJcEVACKBgIAigTjAIoEuwBgBFwAigQmACgEKwANBFQAJgHo/7MEKwANA+YAigOvAIoEIABDAegAlwHo/7MDzwArBFQAigQfACIEhQATBFAAigOvAIoD5gCKBOwAigYCAIoE4wCKBLsAYATOAIoEXACKBHwAYAQmACgEVAAmBD8ARwTjAIoEfABgBCsADQXDAAIE7ACKBB8AIgVnAGAFtwCXBjkACQS7AGAEIABDBhUAMQYVADEGFQAxBCsADQU4ABwEWgBtBIwAqQQ9AF0EhQATA+YAigH6AIUAAQAAB2z+DAAACUn6G/5KCTAAAQAAAAAAAAAAAAAAAAAABQ4AAwSGAZAABQAABZoFMwAAAR8FmgUzAAAD0QBmAgAAAAIAAAAAAAAAAADgAAL/UAAgWwAAACAAAAAAR09PRwBAAAD//QYA/gAAZgeaAgAgAAGfAAAAAAQ6BbAAIAAgAAMAAAABAAAFEAkKBAAAAgICAwYFBwYCAwMEBQICAgQFBQUFBQUFBQUFAgIFBQUECAYGBgYFBQYGAgUGBQgGBgYGBgUFBgYIBgUFAgQCBAQDBQUFBQUDBQUCAgUCCAUFBQUDBQMFBAcEBAQDAgMGAgUFBgUCBgQHBAQFBwQDBQMDAwUEAgIDBAQHBwcECAUGBQUIBQUFBQUGAgUFAgYFCQgCBgMGBQYGAgUEBAQEAgMCBAMDAAAAAAAAAgUCBQYGBgUGBQYGBgUFBQUFBQUFAwUEBQUFBQUFBgYHBQUHBwYKCgcGBgcIBQYGBgcHBggJBwgGBggGBQUEBQcFBQUFBwUFBAcFBQcHBgcFBQcFBQUICAUFCAcFCAcFBQgHCAcKCQUEBgUGBQYFCAcIBwYFBgAAAAAAAAcGBQYFBQQFBQkHBgUGBQcGBwUJBgkIBwUGBQgGBgUGBQYHBQYFBwYGBQcGCAcGBQUFBAYFBgcIBwYFBQkHCQcGBQYGBgcGBAUJBQkDAgIFAgIBAQACAgYHBAICAgIDAwMFBQMEBgIJAwMEAwQFBwcKBwcFBwUFBgYHBAkGBgcICAcFBgUFBQkCBQUFBQUDAwIGBQUICAYHAAkJAwMDBQUFBQUFBQUFBQUFBQcFBQUFBQUFBQYHBAUEAgYFBAUFBAQFBQUEBQQGBgYGBQgIBgUFBgcFBgUFBQYFBwgGBwUFBwUFBwUGBgYFBQcFBQYFBQUFBAkFAwMDAwMDAwQDBAUFBgYFBgUFBQUFAgQABAQFBAQEBAMDAwMDAwMGBgYHBwQFBQUFBQQCBwUCBQUFBQUFBQUFBQICAgICBQYFBQUFBQUFBQUFBAUEBwQFBgYCAgYGBQUDBgYGBgYGBgYFBQUFAgICAgYGBgYGBgYGBgYFBQUFBQUFBQUFBQUFAgICAgUFBQUFBQUFBQUEBAYFBgUGBQYFBgUGBQYFBgYFBQUFBQUFBQUFBgUGBQYFBgUGBQICAgICAgICAgcEBQIGBQUCBQIFAwUDBgUGBQYFBQYFBgUGBQYDBgMGAwUFBQUFBQUFBQUFAwUDBQMGBQYFBgUGBQYFBgUIBwUEBQUEBQQFBAgIBgUFBQUFBQUFBQUFBQQEBAQCAgICBgUFBQUFBQUFBQUFBQUFBQUFBQQEBAQEBQUFBQYCAgICAgQFBAQEBAYGBgUFBQUFBQUFBQUFBQUFBQUFBQUHBQUFBQUGBQYCBgYGAwYGBQUGAgYIBgYGBQUGAgUFBQUDBQUFBQQEAwUFBQcFBQUCAgUGBgYGBgUFBggGBgYGBgUGBQUFBQUFBAQFBAUCAgIFBAgHCAcIBwUEAgMFAgIICAYFBQYFBQYGBgUJCgUFBgUFBQIIBwIGBQYFCAgFBQYFBQgHBQUGBQYFBgUGBQYFBgUGBAYEBgQGBQgHBQYFBgUGBQYFBgUGBQYFBgUGBQYFBgUGBQUFBQUFBQUFBQUFBQUFBQUCAgICBgUGBQYFBgUGBQYFBgUGBQYFBgUGBQYFBgUGBQYGBgYGBgYGBgYFBAUEBQQFBQQGBQUEBwUFBgYFBAYFBQUGBAUFBwUFBQUFBQUFBgUGBQYFBQUCAgYFBgMGBQUGBQYFBgUGBQYFBgUFAggIBgUGBgUGAwUFBQMGBgQGBAgHBQQHBQUGAgUFBgUFBAUGAgUHBgUFBQUFAgUEBAUCAgQFBQUFBAQGBwYFBQUFBQUFBgUFBgYFBgYHBQUHBwcFBgUFBQUEAgAAAAMAAAADAAAAHAADAAEAAAAcAAMACgAABooABAZuAAAA9ACAAAYAdAAAAAIADQB+AKAArACtAL8AxgDPAOYA7wD+AQ8BEQElAScBMAFTAV8BZwF+AX8BjwGSAaEBsAHwAf8CGwI3AlkCvALHAskC3QLz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AxgDGgMcAx4DIAMiAyQDJQMnAykDKwMtA4YDhwOIA4kDigOLA4wDjgOPA5ADkQOSA5MDlAOVA5YDlwOYA5kDmgObA5wDnQOtA64DrwOwA7EDsgOzA7QDtQO2A7cDuAO5A7oDuwO8A70DvgO/A8ADwQPCA9MD1QPXA9kD7gPwA/IEBwQNBBMEfQSCBIYFBwUJAAIAAAACAAo6GAABA/IABAAAAfQHzjTGNMYH/AheNv43rjTMOcw3eghkOBg4GDe4OAI4GDgYOcw4RAwCDNA4ijlYOZQ03jaEObINRjdcOGY1jA2MODoOwjg6ODo3iDhmOHwPxDl2ECY1PDl2EEA4ZjnMEIY1xjb+Ocw2/hEIEgYTCBPqFIw5dhSSFJw4OheGGXgaahtwG4YbjBuSHowekh7MHwIfjDWgNaAhvjgYImAjXjTeJcA4GDgYNUI4GDgYOBgmljWgOBg1oChAKQYpmCn6KuA1lituNTwzRiuYLXI4ZjEAMTozJDMkOGYycDL6MyQzJDMkNv43iDlYOXYzRjhmNcY1ljTeNTw3uDe4N7g4GDTeNTw4GDgYOcw1ljTeNTw0xjNwNMY0xjTGOgg0EjRgOgI0vDnqOfA6AjnwOeo56jnqOeo0rjnwNMw5zDnMOcw5zDiKNv42/jb+Nv42/jb+Nv40zDd6N3o3ejd6OBg4GDgYOBg4GDnMOcw5zDnMOcw2hDdcN1w3XDdcN1w3XDdcNYw1jDWMNYw4OjeIN4g3iDeIN4g5djl2Nv43XDb+N1w2/jdcNMw0zDTMNMw5zDd6NYw3ejWMN3o1jDd6NYw3ejWMOBg4OjgYOBg4GDgYOBg3uDgCOAI4AjgCOBg4OjgYODo4GDg6ODo5zDeIOcw3iDnMN4g4fDh8OHw4ijiKOIo5lDaEOXY2hDmyObI5sjoCOgI6CDnwOfA58DnwOfA58DnwOgI6AjoCOgI6AjnwOfA58DoCOeo0vDS8NLw0vDoCOgI6AjoINv43ejgYOBg5zDaENv43rjd6ObI4GDgYN7g4GDgYOcw4RDiKNoQ03jgYNoQ4OjeIOXY3iDd6NcY4GDgYN7g3uDVCNv43rjXGN3o4GDgYOcw4RDTMOIo03jdcNYw3iDhmOXY1PDWMNZY5djmUOZQ5lDaEOXY0xjTGNMY4GDg6Nv43XDd6NYw5WDl2NMw2hDl2OBg03jU8OBg2/jdcNv43XDd6NYw1jDWMNN41PDnMN4g3iDhmNUI5djVCOXY1Qjl2Nv43XDb+N1w2/jdcNv43XDb+N1w2/jdcNv43XDb+N1w2/jdcNv43XDb+N1w2/jdcN3o1jDd6NYw3ejWMN3o1jDd6NYw3ejWMN3o1jDd6NYw4GDgYOcw3iDnMN4g5zDeIOcw3iDnMN4g5zDeIOcw3iDeINoQ5djaEOXY2hDl2OIo1xjWWODo1oDXGN7g2hDgYODo2/jdcN3o4GDnMN4g4fDeuOGY5zDnMOBg4Oje4N7g4AjgYODo4GDg6Ocw4RDhmOHw4ijlYOXY5WDl2OZQ5sjnMOfA6AjnwOeo6CDnqOfA6AjoIAAIApAAEAAQAAAAGAAYAAQALAAwAAgATABMABAAlACoABQAsAC0ACwAvADYADQA4ADgAFQA6AD8AFgBFAEYAHABJAEoAHgBMAEwAIABPAE8AIQBRAFQAIgBWAFYAJgBYAFgAJwBaAF0AKABfAF8ALACKAIoALQCWAJYALgCdAJ0ALwCxALUAMAC3ALkANQC7ALsAOAC9AL4AOQDAAMEAOwDDAMUAPQDHAM4AQADSANIASADUAN4ASQDgAO8AVADxAPEAZAD2APgAZQD7APwAaAD+AQAAagEDAQUAbQEKAQoAcAENAQ0AcQEYARoAcgEiASIAdQEuATAAdgEzATUAeQE3ATcAfAE5ATkAfQE7ATsAfgFDAUQAfwFUAVQAgQFWAVYAggFYAVgAgwFcAV4AhAGEAYUAhwGHAYkAiQHYAdgAjAHaAdsAjQHdAd0AjwHgAeEAkAHrAe0AkgH/Af8AlQIOAhAAlgIwAjAAmQIzAjMAmgJFAkUAmwJHAkgAnAJ6AnsAngJ9An0AoAJ/ApQAoQKZAqAAtwKiAqUAvwKqAq8AwwK0ArwAyQK+Ar4A0gLAAsAA0wLCAsIA1ALEAsQA1QLGAs8A1gLYAtoA4ALcAtwA4wLeAt4A5ALgAuAA5QLiAuIA5gLnAucA5wLpAukA6ALrAusA6QLtAu0A6gLvAu8A6wLxAv0A7AL/Av8A+QMBAwEA+gMDAwMA+wMOAw4A/AMQAxAA/QMSAxIA/gMgAyAA/wMiAyUBAAMnAycBBAMpAykBBQMvAzgBBgNDA0cBEANNA08BFQNUA1QBGANlA2kBGQNtA28BHgN4A3gBIQOGA4sBIgOOA50BKAOgA6ABOAOkA6QBOQOmA6YBOgOqA6oBOwOtA64BPAOwA7EBPgOzA7kBQAO7A70BRwO/A8QBSgPGA8cBUAPJA8wBUgPSA9MBVgPVA9UBWAPXA9cBWQPZA9wBWgPfA+QBXgPmA+YBZAPqA+sBZQPwA/ABZwPyA/sBaAP+A/8BcgQBBAQBdAQLBAwBeAQQBBABegQSBBgBewQeBEYBggRIBEgBqwRKBFcBrARfBF8BugRwBHUBuwR3BHcBwQR7BHwBwgR/BH8BxASBBIIBxQSEBIQBxwSGBIYByASXBJsByQSdBJ0BzgSfBKABzwSiBKIB0QSmBKgB0gSqBKoB1QSsBK4B1gSwBLAB2QSyBLIB2gS0BLoB2wS8BLwB4gS/BL8B4wTCBMYB5ATIBMgB6QTKBMsB6gTPBM8B7ATSBNIB7QTYBNgB7gTdBN0B7wToBOgB8ATqBOoB8QTxBPEB8gT1BPUB8wALADj/2ADS/9gA1v/YATn/2AFF/9gDDv/YAxD/2AMS/9gDwf/YBHf/2AS//9gAGAA6ABQAOwASAD0AFgEZABQCmQAWAyAAEgMiABYDJAAWA4sAFgOaABYDnQAWA9MAEgPVABID1wASA9kAFgPqABQD8gAWBHAAFgRyABYEdAAWBIYAFgTCABQExAAUBMYAEgABABP/IADnABD/FgAS/xYAJf9WAC7++AA4ABQARf/eAEf/6wBI/+sASf/rAEv/6wBT/+sAVf/rAFb/5gBZ/+oAWv/oAF3/6ACU/+sAmf/rAJv/6gCy/1YAtP9WALv/6wC9/+gAyP/rAMn/6wDL/+oA0gAUANYAFAD3/+sBA//rAQ3/VgEY/+sBGv/oAR7/6wEi/+sBOQAUAUL/6wFFABQBYP/rAWH/6wFr/+sBhv8WAYr/FgGO/xYBj/8WAev/wAHt/8ACM//AAn//VgKA/1YCgf9WAoL/VgKD/1YChP9WAoX/VgKa/94Cm//eApz/3gKd/94Cnv/eAp//3gKg/94Cof/rAqL/6wKj/+sCpP/rAqX/6wKr/+sCrP/rAq3/6wKu/+sCr//rArD/6gKx/+oCsv/qArP/6gK0/+gCtf/oArb/VgK3/94CuP9WArn/3gK6/1YCu//eAr3/6wK//+sCwf/rAsP/6wLF/+sCx//rAsn/6wLL/+sCzf/rAs//6wLR/+sC0//rAtX/6wLX/+sC5f74Avn/6wL7/+sC/f/rAw4AFAMQABQDEgAUAxX/6gMX/+oDGf/qAxv/6gMd/+oDH//qAyP/6AMy/8ADM//AAzT/wAM1/8ADNv/AAzf/wAM4/8ADTf/AA07/wANP/8ADhv9WA47/VgOe/+sDov/qA6T/6wOm/+gDqf/qA6r/6wOr/+oDsv74A7b/VgPBABQDw//eA8T/6wPG/+sDyP/rA8n/6APL/+sD0v/oA9r/6APi/1YD4//eA+b/6wPr/+gD7P/rA/H/6wPz/+gD+P9WA/n/3gP6/1YD+//eA///6wQB/+sEAv/rBAz/6wQO/+sEEP/rBBT/6AQW/+gEGP/oBB3/6wQe/1YEH//eBCD/VgQh/94EIv9WBCP/3gQk/1YEJf/eBCb/VgQn/94EKP9WBCn/3gQq/1YEK//eBCz/VgQt/94ELv9WBC//3gQw/1YEMf/eBDL/VgQz/94ENP9WBDX/3gQ3/+sEOf/rBDv/6wQ9/+sEP//rBEH/6wRD/+sERf/rBEv/6wRN/+sET//rBFH/6wRT/+sEVf/rBFf/6wRZ/+sEW//rBF3/6wRf/+sEYf/rBGP/6gRl/+oEZ//qBGn/6gRr/+oEbf/qBG//6gRx/+gEc//oBHX/6AR3ABQEmf9WBJr/3gSc/+sEoP/rBKT/6gSp/+sEq//rBL8AFATD/+gExf/oBMv/wATS/8AE6v/AADMAOP/VADr/5AA7/+wAPf/dANL/1QDW/9UBGf/kATn/1QFF/9UB6wAOAe0ADgIzAA4Cmf/dAw7/1QMQ/9UDEv/VAyD/7AMi/90DJP/dAzIADgMzAA4DNAAOAzUADgM2AA4DNwAOAzgADgNNAA4DTgAOA08ADgOL/90Dmv/dA53/3QPB/9UD0//sA9X/7APX/+wD2f/dA+r/5APy/90EcP/dBHL/3QR0/90Ed//VBIb/3QS//9UEwv/kBMT/5ATG/+wEywAOBNIADgTqAA4AHQA4/7AAOv/tAD3/0ADS/7AA1v+wARn/7QE5/7ABRf+wApn/0AMO/7ADEP+wAxL/sAMi/9ADJP/QA4v/0AOa/9ADnf/QA8H/sAPZ/9AD6v/tA/L/0ARw/9AEcv/QBHT/0AR3/7AEhv/QBL//sATC/+0ExP/tABEALv/uADn/7gKV/+4Clv/uApf/7gKY/+4C5f/uAxT/7gMW/+4DGP/uAxr/7gMc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/+IAGAA4/+sAPf/zANL/6wDW/+sBOf/rAUX/6wKZ//MDDv/rAxD/6wMS/+sDIv/zAyT/8wOL//MDmv/zA53/8wPB/+sD2f/zA/L/8wRw//MEcv/zBHT/8wR3/+sEhv/zBL//6wA5AFH/7wBS/+8AVP/vAFz/8ADB/+8A7P/vAO3/7gDu//AA8P/vAPH/7wDz/+8A9P/vAPX/7wD2/+4A+P/vAPr/7wD7/+8A/v/vAQD/7wEF/+8BCf/0ASD/8QEr/+8BNP/wATb/7wE6/+8BPP/vAT7/7wFE//ABU//vAVX/7wFX/+8BXP/vAV7/8AFt/+8Cqv/vAvL/7wL0/+8C9v/vAvf/7wOg/+8Dxf/vA8f/7wPK//ADzP/vA9H/7wPh/+8D5//vA/b/8AQE//AECP/vBAr/7wQc/+8EfP/vBJj/7wS1/+8Et//vACMABv/yAAv/8gBa//UAXf/1AL3/9QD2//QBCf/1ARr/9QE6//UBbf/1AYT/8gGF//IBh//yAYj/8gGJ//ICtP/1ArX/9QMj//UDpv/1A8n/9QPS//UD2v/1A9v/8gPc//ID3//yA+v/9QPz//UEFP/1BBb/9QQY//UEcf/1BHP/9QR1//UEw//1BMX/9QAKAO0AFAD2/+0A+f/tAPz/4gE6/+0BSP/tAUr/7QFt/+0EGv/tBHr/7QB2AEf/8ABI//AASf/wAEv/8ABT/+sAVf/wAJT/8ACZ//AAu//wAMj/8ADJ//AA9//wAQP/8AEY/+sBHP/rAR7/8AEi//ABQv/wAWD/8AFh//ABa//wAdv/6wHd/+sB5f/pAez/6wH1/+sCEf/rAhr/6wIx/+sCof/wAqL/8AKj//ACpP/wAqX/8AKr/+sCrP/rAq3/6wKu/+sCr//rAr3/8AK///ACwf/wAsP/8ALF//ACx//wAsn/8ALL//ACzf/wAs//8ALR//AC0//wAtX/8ALX//AC+f/rAvv/6wL9/+sDOf/rA0P/6wNE/+sDRf/rA0b/6wNH/+sDUP/rA1H/6wNS/+sDU//rA1r/6wNb/+sDXP/rA13/6wNt/+sDbv/rA2//6wOe//ADpP/rA6r/6wPE//ADxv/rA8j/8APL//AD5v/wA+z/8APx//AD///wBAH/8AQC//AEDP/rBA7/8AQQ/+sEHf/wBDf/8AQ5//AEO//wBD3/8AQ///AEQf/w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AOwAPgDuAO4APwD3APcAQAD8APwAQQD+AP8AQgEEAQUARAEKAQoARgENAQ0ARwEYARoASAEuATAASwEzATUATgE3ATcAUQE5ATkAUgE7ATsAUwFDAUQAVAFUAVQAVgFWAVYAVwFYAVgAWAFcAV4AWQGEAYoAXAGOAY8AYwHYAdgAZQHdAd0AZgHgAeEAZwHrAe0AaQH/Af8AbAIOAhAAbQIwAjAAcAIzAjMAcQJFAkUAcgJHAkgAcwJ6AnsAdQJ9An0AdwJ/AqUAeAKqAq8AnwK0AsQApQLGAs8AtgLYAtoAwALcAtwAwwLeAt4AxALgAuAAxQLiAuIAxgLlAuUAxwLnAucAyALpAukAyQLrAusAygLtAu0AywLvAu8AzALxAv0AzQL/Av8A2gMBAwEA2wMDAwMA3AMOAw4A3QMQAxAA3gMSAxIA3wMUAxQA4AMWAxYA4QMYAxgA4gMaAxoA4wMcAxwA5AMeAx4A5QMgAyAA5gMiAyoA5wMvAzgA8ANDA0cA+gNNA08A/wNUA1QBAgNlA2kBAwNtA28BCAN4A3gBCwOGA4sBDAOOA50BEgOgA6ABIgOkA6QBIwOmA6YBJAOqA6oBJQOtA64BJgOwA7kBKAO7A70BMgO/A8QBNQPGA8wBOwPSA9MBQgPVA9UBRAPXA9cBRQPZA9wBRgPfA+QBSgPmA+YBUAPqA+sBUQPwA/sBUwP+A/8BXwQBBAQBYQQLBAwBZQQQBBABZwQSBBgBaAQeBEYBbwRIBEgBmARKBFcBmQRfBF8BpwRiBGIBqARkBGQBqQRwBHUBqgR3BHcBsAR7BHwBsQR/BH8BswSBBIIBtASEBIQBtgSGBIYBtwSXBJsBuASdBJ0BvQSfBKABvgSiBKIBwASmBKgBwQSqBKoBxASsBK4BxQSwBLAByASyBLIByQS0BLoBygS8BLwB0QS/BL8B0gTBBMYB0wTIBMsB2QTPBM8B3QTSBNIB3gTYBNgB3wTdBN0B4AToBOgB4QTqBOoB4gTxBPEB4wT1BPUB5AACAXQABgAGABkACwALABkAEAAQACEAEgASACEAJQAlAAIAJgAmABwAJwAnABMAKAAoAAEAKQApAAUALgAuAAoALwAvAAsAMAAwABgAMwAzAAEANAA0ABYAOAA4AA4AOQA5AAoAOgA6AB0AOwA7ABsAPAA8ABIAPQA9AAwAPgA+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AAMAAAAAAAAAAAAAAAAAAAARABUAAAADAAAAAAALAAAAAAADAAAAAwAAAAAAAgABABEAFQALAAAAIAAhAAAAAAAAAAAAAAAAAAAAGQAbAAAAAwAAAAMAAAADAAAAAAAAAAAAAwARABUAAAABAAEAAAAAAAAAAAAZAAAAAAAAAAIAAQAAAAAAAAAZABsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAB8AAAAUABQAGgAUABQAFAAaAAAAAAAAABoAGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcAHAAkAAAAEgAYAB4AAAAIAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAA0ACAANAAAAAAAAAAAAAAAAABgACAAAAAAAGAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAGAAIABcAHAAYAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAA0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgAAAAIAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAABgAGAAYABgAGAAYABgACAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgACAAIAAgAKAAoACgAKAAwABwAHAAcABwAHAAcABwABAAEAAQABAAEAAAAAAAAAAAADAAQABAAEAAQABAAFAAUABQAFAAkACQAGAAcABgAHAAYABwACAAEAAgABAAIAAQACAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAgABAAIAAQACAAEAAgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAwAAAAMAAwACAAQAAgAEAAIABAAAAAAAAAAAAAAAAAAQAA4AEAAOABAADgAQAA4AEAAOAAsAAAALAAAACwAAAAoABQAKAAUACgAFAAoABQAKAAUACgAFABYAAAAMAAkADAATAA8AEwAPABMADwAAAAAAAgAAAAAAAAAAAA0ADQANAA0ADQANAA0ACAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgACAAIAAgAEgASABIAEgAXAA0ADQANAAgACAAIAAgAAAAAAAAAAAAAAAAACAAIAAgACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgACAAAAAAAAAAeAB4AHgAeAAAAGAAAABIAEgASABIAEgASACQAFwAXAAAAAAAAAAYAAAAAAAAAAgAMAAAAAAAGAAAAAAATAAAAAAAAAAAAAAACAAAAAAAMABEAAAAMAAEAAAADAAAABQAAAAQAAAAJAAAAAAAFAAQABQAAAAAAAAAAAAAAAAAjAAAAAAAiAAYAAAAAAAAAAAAAAAAAAgAAAAAAAgALABEABwABAAMABAADAAEACQAVAAEAAwAOAAAAAAAAAAMACQAWAAAAFgAAABYAAAAMAAkAFAAUAAAAAAAUAAAAAwAGAAcAAAAAAAEAAwAAAAAAHQAJAAEAAgAAAAAAAgABAAwACQAAABEAFQAAAAYABwAGAAcAAAAAAAAAAQAAAAEAAQARABUAAAAAAAAAAwAAAAMAAgAEAAIAAQACAAQAAAAAACIACQAiAAkAIgAJACAAIQAAAAMAAQAGAAcABgAHAAYABwAGAAcABgAHAAYABwAGAAcABgAHAAYABwAGAAcABgAHAAYABwAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAAAAAAAAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAIAAQACAAEAAgABAAIABAACAAEACgAFAAoABQAAAAUAAAAFAAAABQAAAAUAAAAFAAwACQAMAAkADAAJAAAACwAAACAAIQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAGAAcAAAABAAAAAAACAAQAAAAAAAAABQAAAAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAADAAIAAAAAAAAAAAAQAA4ACwAAAAoAHQAJAB0ACQAWAAAAEwAPAAAADQAAAAAAAAAIABcAAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXABwAAAAXAAAAAAAAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAgAAAAAAAgAGAAcAAAAAAAIABcAAQAAAAoBYgKSAARERkxUABpjeXJsABpncmVrABpsYXRuAEgABAAAAAD//wASAAAAAQACAAMABAAIAAwADQAOAA8AEAARABIAEwAUABUAFgAXAC4AB0FaRSAA5ENSVCAA5EZSQSAAWk1PTCAAtk5BViAAiFJPTSAAtlRSSyAA5AAA//8AEwAAAAEAAgADAAQABwAIAAwADQAOAA8AEAARABIAEwAUABUAFgAXAAD//wAUAAAAAQACAAMABAAGAAgACQAMAA0ADgAPABAAEQASABMAFAAVABYAFwAA//8AFAAAAAEAAgADAAQABgAIAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAAP//ABQAAAABAAIAAwAEAAYACAAKAAwADQAOAA8AEAARABIAEwAUABUAFgAXAAD//wATAAAAAQACAAMABAAFAAgADAANAA4ADwAQABEAEgATABQAFQAWABcAGGMyc2MAkmNjbXAAmGRsaWcAoGRub20ApmZyYWMArGxpZ2EAtmxpZ2EAvGxpZ2EAyGxudW0A0GxvY2wA1mxvY2wA3GxvY2wA4m51bXIA6G9udW0A7nBudW0A9HNtY3AA+nNzMDEBAHNzMDIBBnNzMDMBDHNzMDQBEnNzMDUBGHNzMDYBHnNzMDcBJHRudW0BKgAAAAEAAAAAAAIAAgAEAAAAAQAKAAAAAQAYAAAAAwAWABcAGQAAAAEACQAAAAQACAAJAAgACQAAAAIACAAJAAAAAQAVAAAAAQAHAAAAAQAFAAAAAQAGAAAAAQAZAAAAAQASAAAAAQATAAAAAQABAAAAAQALAAAAAQAMAAAAAQANAAAAAQAOAAAAAQAPAAAAAQAQAAAAAQARAAAAAQAUABoANgQwB+4IoAjKD24PhA+uD8IP5hAQEEwQYBB0EIgQmhC0EPYRFBFmEawSDhJsEoASsBLSAAEAAAABAAgAAgH6APoB5wJxAdEB0AHPAc4BzQHMAcsBygHJAcgCMwIyAjECMAIoAeYB5QHkAeMB4gHhAeAB3wHeAd0B3AHbAdoB2QHYAdcB1gHVAdQB0wHSAegB6QJzAnUCdAJ2AnICdwJSAeoB6wHsAe0B7gHvAfAB8QHyAfMB9AH1AfYB9wH4AfkB+gH7AfwB/QH+AgACAQT+AgICAwIEAgUCBgIHAggCCQIKAgsCOwINAg4CDwIQBPgCEQITAhQCFQIWAhcCGAIZAhsCHAIeAh0DLwMwAzEDMgMzAzQDNQM2AzcDOAM5AzoDOwM8Az0DPgM/A0ADQQNCA0MDRANFA0YDRwNIA0kDSgNLA0wDTQNOA08DUANRA1IDUwNUA1UDVgNXA1gDWQNaA1sDXANdA14DXwNgA2EDYgNjBP8DZANlA2YDZwNoA2kDagNrA2wDbQNuA28DcANxA3IDcwN0A3UFAgN2A3cDeQN4A3oDewN8A30DfgN/A4ADgQOCA4MDhAOFBQAFAQTLBMwEzQTOBM8E0ATRBNIE0wTUBNUE1gTXBNgE2QTaBNsE3ATdBN4E3wTgBOEE4gTjBOQE5QTmBOcB/wToBOkE6gTrBOwE7QTuBO8E8ATxBPIE8wT0BPUE9gUDBQQFBQUGBPcE+QT6BPwCGgT9BPsCDAISBQsFDAABAPoACAAKABQAFQAWABcAGAAZABoAGwAcAB0AJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQA+AGUAZwCBAIMAhACMAI8AkQCTALEAsgCzALQAtQC2ALcAuAC5ALoA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkBLwEzATUBNwE5ATsBQQFDAUUBSQFLAUwBWAFZAZcBnQGiAaUCegJ7An0CfwKAAoECggKDAoQChQKGAocCiAKJAooCiwKMAo0CjgKPApACkQKSApMClAKVApYClwKYApkCtgK4AroCvAK+AsACwgLEAsYCyALKAswCzgLQAtIC1ALWAtgC2gLcAt4C4ALiAuMC5QLnAukC6wLtAu8C8QLzAvUC+AL6AvwC/gMAAwIDBAMGAwgDCgMMAw4DEAMSAxQDFgMYAxoDHAMeAyADIgMkAyUDJwMpAysDLQOGA4cDiAOJA4oDiwOMA44DjwOQA5EDkgOTA5QDlQOWA5cDmAOZA5oDmwOcA50DrQOuA68DsAOxA7IDswO0A7UDtgO3A7gDuQO6A7sDvAO9A74DvwPAA8EDwgPTA9UD1wPZA+4D8APyBAcEDQQTBH0EggSGBQcFCQABAAAAAQAIAAIB3ADrAnECMwIyAjECMAIoAeYB5QHkAeMB4gHhAeAB3wHeAd0B3AHbAdoB2QHYAdcB1gHVAdQB0wHSAmQCcwMwAnUCdAMvAeMCcgJ3AlIE0gTTAeoB6wTUBNUE1gHsBNcB7QHuAe8E3AHwAfAE3QTeAfEB8gHzAfoE6wTsAfsB/AH9Af4B/wIABO8E8ATyBPUE/gICAgMCBAIFAgYCBwIIAgkCCgILAfQB9QH2AfcB+AH5AjsCDQIOAg8CEAT4AhECEwIUAhUCFwIZAnYDMQMyAzMDNAM1AzYDNwM4AzkDOgM7AzwDPQM+Az8DQANBA0IDQwNEA0UDRgNHA0gDSQNKA0sDTAOCA00DTgNPA1ADUQNSA1MDVANVA1YDVwNYA1kDWgNbA1wDXQNeA18DYANhA2IE/wNkA2UDZgNnA2gDaQNqA2sDbANtA24DbwNwA3EDcgNzA3QDdQUCA3YDdwN5A3gDegN7A3wDfQN+A38DgAOBA4MDhAOFBQAFAQTLBMwEzQTOBNgE2wTZBNoE3wTgBOEEzwTQBNEE6gTtBO4E8QTzBPQCAQT2BOIE4wTkBOUE5gTnBOgE6QUDBQQFBQUGBPcE+QT6AhgE/AIaBP0E+wIWAgwCEgULBQwAAQDrAAoARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAIUAhgCHAIkAigCLAI0AkACSAJQAuwC8AL0AvgC/AMAAwQDCAMMAxADFAMYAxwDIAMkAygDLAMwAzQDOAOoA6wDsAO0A7gDvAPAA8QDyAPMA9AD1APYA9wD4APkA+gD7APwA/QD+AP8BAAEBAQIBAwEEAQUBBgEHATABNAE2ATgBOgE8AUIBRAFGAUoBTQFaAnwCfgKaApsCnAKdAp4CnwKgAqECogKjAqQCpQKmAqcCqAKpAqoCqwKsAq0CrgKvArACsQKyArMCtAK1ArcCuQK7Ar0CvwLBAsMCxQLHAskCywLNAs8C0QLTAtUC1wLZAtsC3QLfAuEC5ALmAugC6gLsAu4C8ALyAvQC9gL5AvsC/QL/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) -} - -@font-face { - font-family: Roboto; - font-weight: 500; - src: url(data:font/ttf;base64,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ERI5ALAARViwAS8bsQEgPlmwAEVYsAUvG7EFID5ZsABFWLADLxuxAxA+WbIAAQMREjkwMQEBIQEjASEClQFyARb99PX99gEVAT0Ec/pQBbAAAQAwAAAG5QWwAAwAYLIFDQ4REjkAsABFWLABLxuxASA+WbAARViwCC8bsQggPlmwAEVYsAsvG7ELID5ZsABFWLADLxuxAxA+WbAARViwBi8bsQYQPlmyAAEDERI5sgUBAxESObIKAQMREjkwMQETMwEjAQEjATMTATMFCuD7/rDy/uv+5fP+sPviARbUAWgESPpQBCf72QWw+7oERgABACkAAATpBbAACwBTALAARViwAS8bsQEgPlmwAEVYsAovG7EKID5ZsABFWLAELxuxBBA+WbAARViwBy8bsQcQPlmyAAEEERI5sgYBBBESObIDAAYREjmyCQYAERI5MDEBASEBASEBASEBASECiQEyAST+SAHC/tn+x/7G/toBw/5HASQDogIO/S79IgIW/eoC3gLSAAABAAcAAATWBbAACAAxALAARViwAS8bsQEgPlmwAEVYsAcvG7EHID5ZsABFWLAELxuxBBA+WbIAAQQREjkwMQEBIQERIxEBIQJvAU8BGP4Y/v4XARkC/gKy/Gj96AIYA5gAAAEAUAAABIwFsAAJAEYAsABFWLAHLxuxByA+WbAARViwAi8bsQIQPlmxAAGwCitYIdgb9FmyBAACERI5sAcQsQUBsAorWCHYG/RZsgkFBxESOTAxJSEVITUBITUhFQGCAwr7xALx/RQEH8rKpARAzKAAAAEAhP68AhwGjgAHACQAsAQvsAcvsQABsAorWCHYG/RZsAQQsQMBsAorWCHYG/RZMDEBIxEzFSERIQIcpaX+aAGYBdD5qb0H0gAAAQAU/4MDZAWwAAMAEwCwAi+wAEVYsAAvG7EAID5ZMDETMwEjFPACYPAFsPnTAAEADP68AaYGjgAHACcAsAIvsAEvsAIQsQUBsAorWCHYG/RZsAEQsQYBsAorWCHYG/RZMDETIREhNTMRIwwBmv5mp6cGjvguvQZXAAABADUC2QM1BbAABgAnsgAHCBESOQCwAEVYsAMvG7EDID5ZsADQsgEHAxESObABL7AF0DAxAQMjATMBIwG1ss4BK6sBKs0Epv4zAtf9KQABAAP/QQOYAAAAAwAcALAARViwAy8bsQMQPlmxAAGwCitYIdgb9FkwMQUhNSEDmPxrA5W/vwABADEE0QIJBgAAAwAkALABL7IPAQFdsAPQsAMvtA8DHwMCXbIAAQMREjkZsAAvGDAxASMBIQIJyv7yARUE0QEvAAACAFr/7AP7BE4AHgApAIiyFyorERI5sBcQsCDQALAARViwFy8bsRccPlmwAEVYsAQvG7EEED5ZsABFWLAALxuxABA+WbICFwQREjmyCxcEERI5sAsvsBcQsQ8BsAorWCHYG/RZshILDxESOUAJDBIcEiwSPBIEXbAEELEfAbAKK1gh2Bv0WbALELEjB7AKK1gh2Bv0WTAxISYnBiMiJjU0JDMzNTQmIyIGFSM0NjYzMhYXERQXFSUyNjc1IyIGFRQWAwMQDHSoo84BAe+VXmBTavN2y32+4gMp/f1IfyCDh4hdH0Z5uomtuUdUZVNAWZtYv63+GJJXEa9GO8xeVkZTAAACAHz/7AQyBgAADwAbAGayExwdERI5sBMQsAzQALAJL7AARViwDC8bsQwcPlmwAEVYsAMvG7EDED5ZsABFWLAGLxuxBhA+WbIFDAMREjmyCgwDERI5sAwQsRMBsAorWCHYG/RZsAMQsRgBsAorWCHYG/RZMDEBFAIjIicHIxEzETYzMhIRJzQmIyIHERYzMjY3BDLhxb5qDNzzabLG4vN8dp5AQZ9yfAICEvz+1ol1BgD90nz+2v74B7Cwiv5CjaqsAAEAT//sA/UETgAcAE2yAB0eERI5ALAARViwDy8bsQ8cPlmwAEVYsAgvG7EIED5ZsQABsAorWCHYG/RZsgMIDxESObITDwgREjmwDxCxFgGwCitYIdgb9FkwMSUyNjczDgIjIgARNTQAMzIWFyMmJiMiBgcVFBYCOVt4BOUEdsp14/72AQjkwfMG5QR3XHaAAX+uak5lr2YBJgEDGfcBKeG3XXirriewrQAAAgBP/+wEAwYAAA4AGQBmshcaGxESObAXELAD0ACwBi+wAEVYsAMvG7EDHD5ZsABFWLAMLxuxDBA+WbAARViwCC8bsQgQPlmyBQMMERI5sgoDDBESObAMELESAbAKK1gh2Bv0WbADELEXAbAKK1gh2Bv0WTAxEzQSMzIXETMRIycGIyICNxQWMzI3ESYjIgZP6MOsavPcDG22vuvzf3WVRUOVdoACJfoBL3gCKvoAcIQBMvKluYUBzoK7AAACAFP/7AQLBE4AFQAdAIayFh4fERI5sBYQsAjQALAARViwCC8bsQgcPlmwAEVYsAAvG7EAED5ZshoACBESObAaL7S/Gs8aAl20XxpvGgJxtB8aLxoCcbTvGv8aAnGyjBoBXbEMB7AKK1gh2Bv0WbAAELEQAbAKK1gh2Bv0WbISCAAREjmwCBCxFgGwCitYIdgb9FkwMQUiADU1NDY2MzISERUhFhYzMjcXBgYDIgYHITUmJgJZ5/7hfeKL3fH9PQudd6dpg0HZpGR7EQHPCHIUASPyHqL/jv7m/v5ihpyHfWFrA5+MfRJ6fQABAC0AAALWBhUAFABVsgcVFhESOQCwAEVYsAgvG7EIIj5ZsABFWLAELxuxBBw+WbAARViwAC8bsQAQPlmwBBCwENCxEwGwCitYIdgb9FmwAdCwCBCxDQGwCitYIdgb9FkwMTMRIzUzNTQ2MzIXByYjIhUVMxUjEdKlpci0QEgGKDWu3NwDhrRjtMQSvgizYLT8egAAAgBS/lYEDAROABkAJACGsiIlJhESObAiELAL0ACwAEVYsAMvG7EDHD5ZsABFWLAGLxuxBhw+WbAARViwCy8bsQsSPlmwAEVYsBcvG7EXED5ZsgUDFxESObALELERAbAKK1gh2Bv0WbIPERcREjmyFQMXERI5sBcQsR0BsAorWCHYG/RZsAMQsSIBsAorWCHYG/RZMDETNBIzMhc3MxEUBCMiJic3FjMyNjU1BiMiAjcUFjMyNxEmIyIGUu3EuWoL2/734XfjO3NwpHmMaa++8fKFdpNHRZN4hQIl/AEtgW3759X2Y1CShYN/SXUBLvaju34B3Hu+AAABAHkAAAP4BgAAEABDsgoREhESOQCwEC+wAEVYsAIvG7ECHD5ZsABFWLANLxuxDRA+WbAARViwBi8bsQYQPlmwAhCxCgGwCitYIdgb9FkwMQE2MyATESMRNCYjIgcRIxEzAWx3tgFaBfNhXpJI8/MDxIr+df09ArpwXYL8+wYAAAIAfQAAAZAF1QADAA0AP7IGDg8REjmwBhCwAdAAsABFWLACLxuxAhw+WbAARViwAS8bsQEQPlmwAhCwDNCwDC+xBg2wCitYIdgb9FkwMSEjETMBNDYyFhUUBiImAX/z8/7+R4RISIRHBDoBGThKSjg3SUkAAv+1/ksBhQXVAAwAFgBLsgMXGBESObADELAQ0ACwAEVYsAwvG7EMHD5ZsABFWLAELxuxBBI+WbEJAbAKK1gh2Bv0WbAMELAV0LAVL7EPDbAKK1gh2Bv0WTAxAREUBiMiJzUWMzI3EQM0NjIWFRQGIiYBeqWfQz4mMHkDFUeESEiERwQ6+2amrxHACYQEowEZOEpKODdJSQABAH0AAAQ2BgAADABTALAARViwBC8bsQQiPlmwAEVYsAgvG7EIHD5ZsABFWLACLxuxAhA+WbAARViwCy8bsQsQPlmyAAgCERI5tGoAegACXbIGCAIREjm0ZQZ1BgJdMDEBBxEjETMRNwEhAQEhAdxs8/NMASsBJP5uAb3+5wHQb/6fBgD8il8BUf49/YkAAQCMAAABfwYAAAMAHQCwAEVYsAIvG7ECIj5ZsABFWLAALxuxABA+WTAxISMRMwF/8/MGAAAAAQB8AAAGeQROAB0AeLIEHh8REjkAsABFWLADLxuxAxw+WbAARViwBy8bsQccPlmwAEVYsAAvG7EAHD5ZsABFWLAbLxuxGxA+WbAARViwFS8bsRUQPlmwAEVYsAwvG7EMED5ZsgEDGxESObIFBxUREjmwBxCxEAGwCitYIdgb9FmwGNAwMQEXNjMyFzYzMhYXESMRNCYjIgYHEyMRJiMiBxEjEQFhB3LG2VB21rOvAvNaaFNpFQHzBb6SPfMEOnGFpqbGwf05AsBnYFlI/RoCyL93/PAEOgAAAQB5AAAD+AROABAAVLILERIREjkAsABFWLADLxuxAxw+WbAARViwAC8bsQAcPlmwAEVYsA4vG7EOED5ZsABFWLAHLxuxBxA+WbIBDgMREjmwAxCxCwGwCitYIdgb9FkwMQEXNjMgExEjETQmIyIHESMRAV4HeMMBUgbzWWWTSPMEOn2R/n39NQK9Z2OF/P4EOgACAE//7AQ9BE4ADwAaAEWyDBscERI5sAwQsBjQALAARViwBC8bsQQcPlmwAEVYsAwvG7EMED5ZsRIBsAorWCHYG/RZsAQQsRgBsAorWCHYG/RZMDETNDY2MzIAFxcUBgYjIgA1FxQWMjY1NCYjIgZPfuSU2wERCwF75Zbl/u3zivaJjXl3jAInn/+J/ubpOaD8igEx/gmnvcC5pMC9AAIAfP5gBDAETgAPABoAcLITGxwREjmwExCwDNAAsABFWLAMLxuxDBw+WbAARViwCS8bsQkcPlmwAEVYsAYvG7EGEj5ZsABFWLADLxuxAxA+WbIFDAMREjmyCgwDERI5sAwQsRMBsAorWCHYG/RZsAMQsRgBsAorWCHYG/RZMDEBFAIjIicRIxEzFzYzMhIRJzQmIyIHERYzMjYEMOTAsmvz4ApruMbh8oF4lUFClnSDAhL7/tV1/f8F2m6C/tn++gaivnv+IH67AAACAE/+YAQCBE4ADgAZAG2yFxobERI5sBcQsAPQALAARViwAy8bsQMcPlmwAEVYsAYvG7EGHD5ZsABFWLAILxuxCBI+WbAARViwDC8bsQwQPlmyBQMMERI5sgoDDBESObESAbAKK1gh2Bv0WbADELEXAbAKK1gh2Bv0WTAxEzQSMzIXNzMRIxEGIyICNxQWMzI3ESYjIgZP6Ma1ag7Y82qqwurzg3SQRkaOdIUCJv4BKn9r+iYB/HABL/amvXsB7Ha6AAEAfAAAArQETgANAEeyCQ4PERI5ALAARViwCC8bsQgcPlmwAEVYsAsvG7ELHD5ZsABFWLAFLxuxBRA+WbALELECAbAKK1gh2Bv0WbIJCwUREjkwMQEmIyIHESMRMxc2MzIXArMwM6c68+gGWJw0IgNcCID9HAQ6eY0OAAABAEv/7APKBE4AJgBrsgknKBESOQCwAEVYsAkvG7EJHD5ZsABFWLAcLxuxHBA+WbICHAkREjmwAhCwFtCwCRCxEAGwCitYIdgb9FmyDRYQERI5tAwNHA0CXbAcELEkAbAKK1gh2Bv0WbIhJAIREjm0AyETIQJdMDEBNCYmJyY1NDYzMhYVIzQmIyIGFRQWBBYWFRQGIyImJjUzFhYzMjYC22v4U7bstsLv82hWUGVeAR6jT/LEhdB07AV4Y2BkASZBRDQoWKeMvMCZRl1KPjg+P1d6V5K1YKhhVl1JAAABAAj/7AJyBUEAFABUsgAVFhESOQCwAEVYsBMvG7ETHD5ZsABFWLANLxuxDRA+WbATELAB0LAA0LAAL7ABELEEAbAKK1gh2Bv0WbANELEIAbAKK1gh2Bv0WbAEELAQ0DAxAREzFSMRFBYzMjcVBiMgEREjNTMRAa2/vzE/KitTTf7osrIFQf75tP2kPjcKvBcBNQJltAEHAAEAd//sA/cEOgAQAFSyChESERI5ALAARViwBy8bsQccPlmwAEVYsA0vG7ENHD5ZsABFWLACLxuxAhA+WbAARViwDy8bsQ8QPlmyAAINERI5sAIQsQoBsAorWCHYG/RZMDElBiMiJjURMxEUMzI3ETMRIwMMa8WwtfOrsT7z5Wp+zsMCvf1Gzn8DCfvGAAABABYAAAPaBDoABgA4sgAHCBESOQCwAEVYsAEvG7EBHD5ZsABFWLAFLxuxBRw+WbAARViwAy8bsQMQPlmyAAUDERI5MDEBEzMBIwEzAfrl+/6J0/6G/AE0Awb7xgQ6AAABACEAAAXMBDoADABgsgUNDhESOQCwAEVYsAEvG7EBHD5ZsABFWLAILxuxCBw+WbAARViwCy8bsQscPlmwAEVYsAMvG7EDED5ZsABFWLAGLxuxBhA+WbIACwMREjmyBQsDERI5sgoLAxESOTAxARMzASMDAyMBMxMTMwQzrO3+2cjo5Mj+2O2v3rcBTwLr+8YC5/0ZBDr9HQLjAAABAB8AAAPoBDoACwBTALAARViwAS8bsQEcPlmwAEVYsAovG7EKHD5ZsABFWLAELxuxBBA+WbAARViwBy8bsQcQPlmyAAoEERI5sgYKBBESObIDAAYREjmyCQYAERI5MDEBEyEBASEDAyEBASECAc4BDv61AVb+9NjX/vIBVv62AQwC1gFk/ev92wFy/o4CJQIVAAEADP5LA9YEOgAPAECyABARERI5ALAARViwDy8bsQ8cPlmwAEVYsAUvG7EFEj5ZsgAFDxESObAPELAB0LAFELEJAbAKK1gh2Bv0WTAxARMhAQIjIic1FzI2NzcBIQH33AED/lJj7TVALlxdGyP+hAEGAVwC3vsi/u8SvANDT10ENQABAFIAAAPABDoACQBGALAARViwBy8bsQccPlmwAEVYsAIvG7ECED5ZsQABsAorWCHYG/RZsgQAAhESObAHELEFAbAKK1gh2Bv0WbIJBQcREjkwMSUhFSE1ASE1IRUBgAJA/JICJf3lA0/Cwp8C18SaAAABADj+mAKRBj0AFwA3shIYGRESOQCwDC+wAEVYsAAvG7EAGD5ZsgYADBESObAGL7EFB7AKK1gh2Bv0WbISBQYREjkwMQEkAzU0IzUyNTU2NjcXBgcVFAcWFRUWFwJh/p8HwcEDtbAwrQatrQat/phjAWDV4bLi1LTeMow4+tjhW1zj1fo4AAEArv7yAVUFsAADABMAsAAvsABFWLACLxuxAiA+WTAxASMRMwFVp6f+8ga+AAABABv+mAJ1Bj0AGAA3sgUZGhESOQCwCy+wAEVYsBgvG7EYGD5ZshEYCxESObARL7ESB7AKK1gh2Bv0WbIFEhEREjkwMRc2NzU0NyY1NSYnNxYWFRUUMxUiFRUUBgcbsAS2tgSwMLaywsKztds5/9DnVlbqz/85jDPlucjhsuHFu+UzAAABAHUBgwTcAy8AFwBBshEYGRESOQCwDy+yAxgPERI5sAMvsA8QsQgBsAorWCHYG/RZsAMQsAvQsAMQsRQBsAorWCHYG/RZsA8QsBfQMDEBFAYjIi4CIyIGFSM0NjMyHgIzMjY1BNy+jkp9mkMmQ03BtpRKhZFDJ0NUAxKw3ziJIWhUq9s7hCJwVAACAIb+lAGZBE0AAwAPAD+yBxARERI5sAcQsADQALAARViwDS8bsQ0cPlmwAEVYsAMvG7EDGD5ZsA0QsQcNsAorWCHYG/RZsADQsAAvMDETMxMhARQGIyImNTQ2MzIWqtEY/v8BB0hBQkhIQkFIApb7/gU3OEtLODdLSwAAAQBk/wsECgUmACAAX7IbISIREjkAsABFWLARLxuxERw+WbAARViwCi8bsQoQPlmxAAGwCitYIdgb9FmyAwoRERI5sAoQsAfQsAcvsBEQsBTQsBQvshgRChESObARELEbAbAKK1gh2Bv0WTAxJTI2NzMGBgcVIzUmAjU1NBI3NTMVFhYXIyYmIyIDBxQWAk9ZeAbkBMWSyLfMzLfInrkE5Ad2W+YQAX+uaFCIzRzq6iIBH9wc1QEgIuHgHNicYHX+yEiwrQAAAQBeAAAEfAXDAB8AaLIaICEREjkAsABFWLASLxuxEiA+WbAARViwBS8bsQUQPlmxBAGwCitYIdgb9FmwCNCyHgUSERI5sB4vsR8BsAorWCHYG/RZsAzQsB4QsA/QshYFEhESObASELEZAbAKK1gh2Bv0WTAxARcUByEHITUzNjY1JyM1Myc0NiAWFSM0JiMiBhUXIRUB/QdAArgB++dSJysHoZsI+gGW6PVpXllnCQE3Alawh1XKyglvW7nH8srq2rhfaYJo8scAAAIAXf/lBU8E8QAbACgAQbICKSoREjmwAhCwH9AAsABFWLACLxuxAhA+WbAQ0LAQL7ACELEgB7AKK1gh2Bv0WbAQELEmB7AKK1gh2Bv0WTAxJQYjIicHJzcmNTQ3JzcXNjMyFzcXBxYVFAcXBwEUFhYyNjY0JiYiBgYEPZ/Lyp6BjYdkbZCNjpvAwpuRjpRrYouO/Hhuvty+bW293r5ta39+hJCJnMXIpZOQkXN1lJGXn8rBnI2RAnt4znV2zu7MdXXMAAABAAsAAAQ0BbAAFgBxsgAXGBESOQCwAEVYsAEvG7EBID5ZsABFWLALLxuxCxA+WbIACwEREjmyBwELERI5sAcvsAPQsAMvsQUDsAorWCHYG/RZsAcQsQkDsAorWCHYG/RZsA3QsAcQsA/QsAUQsBHQsAMQsBPQsAEQsBXQMDEBASEBMxUhFSEVIREjESE1ITUhNTMBIQIhAQYBDf6r6v7RAS/+0fz+zAE0/sz4/qkBEQNPAmH9NpiKl/7TAS2XipgCygAAAgCI/vIBbQWwAAMABwAYALAAL7AARViwBi8bsQYgPlmyBQEDKzAxExEzEREjETOI5eXl/vIDG/zlA8gC9gACAFr+JgSMBcQALwA9AIayID4/ERI5sCAQsDDQALAHL7AARViwIC8bsSAgPlmyOSAHERI5sDkQsRMBsAorWCHYG/RZsgI5ExESObAHELEOAbAKK1gh2Bv0WbILDhMREjmyMiAHERI5sDIQsSwBsAorWCHYG/RZshoyLBESObAgELEnAbAKK1gh2Bv0WbIkLCcREjkwMQEUBxYVFAQjIiQ1NxQWMzI2NTQmJy4CNTQ3JiY1NCQzMgQVIzQmIyIGFRQWBBYWJSYnBhUUFh8CNjU0JgSMq4f+8ur2/uDynIh5jYa7vL5dqUFEARPm8AEM85F4e4t4AYPCWv3NUUxsY5WzLnOIAce4WWS5rcbZzwFueF9PTVs3M26abbhaMohkqszhzGqAX1JUV2hxmW4VHCh8UVYvNRAvdVFhAAIAXQTfAyMFzAAIABEAIwCwBy+yDwcBXbECBbAKK1gh2Bv0WbAL0LAHELAQ0LAQLzAxEzQ2MhYUBiImJTQ2MhYUBiImXUN2RER2QwHJQ3ZERHZDBVYyRERkREQxMkREZEREAAADAFf/7AXiBcQAGgAoADYAkrIfNzgREjmwHxCwCdCwHxCwM9AAsABFWLAzLxuxMxA+WbAt0LAtL7ICMy0REjmwAi+0DwIfAgJdsgktMxESObAJL7QACRAJAl2yDQkCERI5sRACsAorWCHYG/RZsAIQsRcCsAorWCHYG/RZshoCCRESObAtELEfCLAKK1gh2Bv0WbAzELElCLAKK1gh2Bv0WTAxARQGICY1NTQ2MzIWFSM0JiMiBhUVFBYzMjY1JTQCJCMiBAIQEgQgJBIlNBIkIAQSEAIEIyIkAgRer/7Avb+eo62cXFhcZ2hbWVoBppb+7qOf/u+cmwERAUABE5j677sBSwGAAUq7u/64wsH+t7wCVJii1bRxrtWllWBTiHZ1doZRYoWmAR2rpP7g/qz+4KeqASCnygFax8f+pv5s/qbJyAFaAAIAjQKzAxEFxAAaACQAkrINJSYREjmwDRCwHNAAsABFWLAULxuxFCA+WbIDJRQREjmwAy+wANCwAC+yAQMUERI5sgoDFBESObAKL7AUELENArAKK1gh2Bv0WbIQCg0REjmyzBABXUATDBAcECwQPBBMEFwQbBB8EIwQCV2yuhABcbADELEbArAKK1gh2Bv0WbAKELEfArAKK1gh2Bv0WTAxAScGIyImNTQ2MzM1NCMiBhUnNDYzMhYVERQXJTI2NzUjBgYVFAJgEU18doOorWZ0QUmtr4iJmhr+oChUG2pMVgLBRFJ7aW55M38zMA5ogZGE/sRhUYIkGYkBPDFYAP//AFcAigOFA6kAJgGS6wAABwGSAVIAAAABAH8BdgPCAyUABQAbALAEL7AB0LABL7AEELECAbAKK1gh2Bv0WTAxASMRITUhA8LI/YUDQwF2AQSrAAAEAFf/7AXiBcQADQAbADEAOgChsgo7PBESObAKELAS0LAKELAx0LAKELAz0ACwAEVYsAMvG7EDID5ZsABFWLAKLxuxChA+WbADELESCLAKK1gh2Bv0WbAKELEYCLAKK1gh2Bv0WbIdCgMREjmwHS+yHwMKERI5sB8vtAAfEB8CXbIyHR8REjmwMi+xHAiwCitYIdgb9FmyJRwyERI5sB0QsCzQsB8QsToIsAorWCHYG/RZMDETNBIkIAQSEAIEIyIkAiU0AiQjIgQCEBIEICQSJREjESEyFhUUBxYWFBYXFSMmNTQmIyczMjY1NCYnI1e7AUsBgAFKu7v+uMLB/re8BRGW/u6jn/7vnJsBEQFAAROY/SWXARmZrHhBNAcKmw1CTZ6PRV1HXY0C2coBWsfH/qb+bP6mycgBWsumAR2rpP7g/qz+4KeqASBb/q8DUod9dT8db6NEFxAioExDhj42RjsBAAEAmwUMA0oFqgADABmyAQQFERI5ALACL7EAA7AKK1gh2Bv0WTAxASE1IQNK/VECrwUMngACAH8DrwKLBcQACQATADuyABQVERI5sArQALAARViwAC8bsQAgPlmwCtCwCi+xBQKwCitYIdgb9FmwABCxEAKwCitYIdgb9FkwMQEyFhQGIyImNDYTMjY1NCYiBhQWAYdqmphsbZudazVFRWpISQXEntybm9ye/nhHNTRMTGhIAAIAXwABA/ME/AALAA8ASACwCS+wAEVYsA0vG7ENED5ZsAkQsADQsAkQsQYBsAorWCHYG/RZsAPQsA0QsQ4BsAorWCHYG/RZsgUOBhESObQLBRsFAl0wMQEhFSERIxEhNSERMwEhNSECnAFX/qnY/psBZdgBMvyvA1EDg8f+fAGExwF5+wXEAAABADwCmwKyBbsAFwBbsggYGRESOQCwAEVYsA8vG7EPID5ZsABFWLAALxuxABQ+WbEWArAKK1gh2Bv0WbICABYREjmyAw8AERI5sA8QsQgCsAorWCHYG/RZsgwPABESObITDwAREjkwMQEhNQE2NTQmIyIGFSM0NjMyFhUUDwIhArL9nAEdcTY0OkK6qYePnGpijAFzApt9AQVnQyo1QjZ0mYBza2ZXcQABADcCkAKpBbsAJACAsh4lJhESOQCwAEVYsA0vG7ENID5ZsABFWLAXLxuxFxQ+WbIBFw0REjl8sAEvGLZAAVABYAEDcbKQAQFdsA0QsQYCsAorWCHYG/RZsgkBDRESObABELEjArAKK1gh2Bv0WbISIwEREjmyGxcNERI5sBcQsR4CsAorWCHYG/RZMDEBMzI1NCYjIgYVIzQ2MzIWFRQHFhUUBiMiJjUzFBYzMjY1NCcjAQxRhDY+MEG6pYKPo4eVsY+Hq7pFPD89hlwEbWEjNScjY3x5aXczKY5qfn9xJjU3KmUBAAEAcATRAkgGAAADACMAsAIvsg8CAV2wANCwAC+0DwAfAAJdsAIQsAPQGbADLxgwMQEhASMBMwEV/uvDBgD+0QABAJL+YAQfBDoAEgBhsg0TFBESOQCwAEVYsAAvG7EAHD5ZsABFWLAHLxuxBxw+WbAARViwEC8bsRASPlmwAEVYsA0vG7ENED5ZsABFWLAKLxuxChA+WbANELEEAbAKK1gh2Bv0WbILDQcREjkwMQERFhYzMjcRMxEjJwYjIicRIxEBhAJZaqg7898HXJN5TfIEOv2EjYJ5AxL7xlZrN/4+BdoAAAEARQAAA1YFsAAKACuyAgsMERI5ALAARViwCC8bsQggPlmwAEVYsAAvG7EAED5ZsgEACBESOTAxIREjIiQ1NCQzIREChFDm/vcBCuYBIQII/tbV//pQAAABAI4CRQGpA1IACgAXsggLDBESOQCwAi+wCLAKK1jYG9xZMDETNDYyFhUUBiMiJo5KhktOQEFMAso6Tk46O0pKAAABAG3+QQHJAAMADgA1sgkPEBESOQCwBi+wAEVYsA4vG7EOED5ZsAYQsAewCitY2BvcWbINBw4REjmyAQ0OERI5MDElBxYVFAYjJzI2NTQmJzcBPguWrJsHQkdHUCADNhuSaXaJLyotIwWLAAABAIACmwICBa4ABgA6sgEHCBESOQCwAEVYsAUvG7EFID5ZsABFWLAALxuxABQ+WbIEBQAREjmwBBCxAwKwCitYIdgb9FkwMQEjEQc1JTMCArnJAW8TApsCOjCSdwAAAgB3ArIDLAXEAAwAGgBCsgkbHBESObAJELAQ0ACwAEVYsAIvG7ECID5ZsgkbAhESObAJL7EQArAKK1gh2Bv0WbACELEXArAKK1gh2Bv0WTAxEzQ2IBYVFRQGIyImNRcUFjMyNjc1NCYjIgYVd78BNsC8nZ6+r11QTlsBXU9OXQRhoMPCpkifw8SjBWJubGFQYW5tZgD//wBdAIoDmQOpACYBkwkAAAcBkwF+AAD//wBZAAAFgwWrACcBxv/ZApgAJwGUARsACAEHAiACxQAAABAAsABFWLAFLxuxBSA+WTAx//8AUAAABcwFrgAnAZQA8AAIACcBxv/QApsBBwHFAxoAAAAQALAARViwCS8bsQkgPlkwMf//AGcAAAX8BbsAJwGUAagACAAnAiADPgAAAQcCHwAwApsAEACwAEVYsCAvG7EgID5ZMDEAAgBC/n8DpQROABkAIwBjshAkJRESObAQELAd0ACwAEVYsCEvG7EhHD5ZsABFWLAQLxuxEBg+WbAhELEdDbAKK1gh2Bv0WbAA0LAAL7IDABAREjmwEBCxCQGwCitYIdgb9FmyDBAAERI5shYQABESOTAxAQYGBwcGFRQWMzI2NTMGBiMiJjU0Nzc2NzcTFAYiJjU0NjIWAnYCNUlnWmJZWGrzAu/CzuKbXE4KAvdHhEhIhEcClXyRT2phal5dZFOx0Mm4paNdSHM1ATc4S0s4N0tLAAAC//YAAAdXBbAADwASAHsAsABFWLAGLxuxBiA+WbAARViwAC8bsQAQPlmwAEVYsAQvG7EEED5ZshEGABESObARL7ECAbAKK1gh2Bv0WbAGELEIAbAKK1gh2Bv0WbILBgAREjmwCy+xDAGwCitYIdgb9FmwABCxDgGwCitYIdgb9FmyEgYAERI5MDEhIQMhAyEBIRUhEyEVIRMhASEDB1f8fg/+Crj+3gNDA+D9ehECJP3kFAKX+u0BeRsBVP6sBbDF/mjF/jYBZwKIAAABAE0A1gPsBIYACwA4ALADL7IJDAMREjmwCS+yCgkDERI5sgQDCRESObIBCgQREjmwAxCwBdCyBwQKERI5sAkQsAvQMDETAQE3AQEXAQEHAQFNATz+xJQBOwE8lP7EATyU/sT+xQFsAUIBQpb+vgFClv6+/r6WAUH+vwAAAwBp/6EFIgXuABcAIAApAGiyECorERI5sBAQsB3QsBAQsCbQALAARViwEC8bsRAgPlmwAEVYsAQvG7EEED5ZshoQBBESObIjEAQREjmwIxCwG9CwEBCxHQGwCitYIdgb9FmwGhCwJNCwBBCxJgGwCitYIdgb9FkwMQEUAgQjIicHIzcmETU0EiQzMhc3MwcWEwUUFwEmIyICBwU0JwEWMzISNQUilP7ttKSEW6mRw5YBFLLFj1enk50B/ERHAfZXh6S5AgK/LP4XTmmptQKy1v69rUuW7sMBZ0PVAUSvZY/zwf7DS8+AAzpV/v/rCKZy/Nw2AQD2AAACAJQAAAR+BbAADAAUAFmyAhUWERI5sAIQsA/QALAARViwAC8bsQAgPlmwAEVYsAovG7EKED5ZsgEKABESObABL7IOCgAREjmwDi+xCQGwCitYIdgb9FmwARCxDQGwCitYIdgb9FkwMQERMzIEFRQEIyMRIxETETMyNjQmJwGH8fQBEv7u8/Lz8/Z9kYx6BbD+6O7Ix+/+1AWw/iX+GoLehAIAAAEAiP/sBJsGFQAsAF2yIy0uERI5ALAARViwBS8bsQUiPlmwAEVYsBUvG7EVED5ZsABFWLAALxuxABA+WbIOBRUREjmwFRCxHAGwCitYIdgb9FmyIhUFERI5sAUQsSoBsAorWCHYG/RZMDEhIxE0NjMyFhUUDgIVFB4CFRQGIyImJzcWFjMyNjU0LgI1NDY1NCYjIgcBevLlzrvXG0UWQbJR2cZQqyYxLX82YVpGrlF+XFC4BARR1u67qT5icUEnLFSUiUuruScZwxwlVkMxW4iIUFjJTVFh9wAAAwBI/+wGhARQACkANAA8ANCyAj0+ERI5sAIQsC3QsAIQsDjQALAARViwFy8bsRccPlmwAEVYsAUvG7EFED5ZsADQsAAvsgwFFxESObAML7KPDAFdsBcQsRABsAorWCHYG/RZsBcQsBvQsBsvsjgAGxESObA4L7QfOC84AnG07zj/OAJxtF84bzgCcbS/OM84Al2yjDgBXbEgB7AKK1gh2Bv0WbAAELEjAbAKK1gh2Bv0WbAFELEqAbAKK1gh2Bv0WbAMELEvB7AKK1gh2Bv0WbAbELE1AbAKK1gh2Bv0WTAxBSInBgYjIiY1NDYzMzU0JiMiBhUnNDYzMhc2FzISFRUhFhYzMjc3FwYGJTI2NzUjBgYVFBYBIgYHITU0JgTm/YxB1oawyO7pv19YW3Py/cXfb4PI1O79SQmYholrPUlG0fyYOogtxGh4XQMrY38QAcRtFKFNVLCcnqxHW2dZQhOSuYWHAv7964mLnjoipjhAuDsr0QJfRkFPAueKfx5xegACAGf/7ARABiwAHQArAGiyBywtERI5sAcQsCjQALAARViwGS8bsRkiPlmwAEVYsAcvG7EHED5Zsg8HGRESObAPL7IRDwcREjmwGRCxGAGwCitYIdgb9FmwDxCxIgGwCitYIdgb9FmwBxCxKAGwCitYIdgb9FkwMQESERUUAgYjIiYmNTQ2NjMyFyYnByc3Jic3Fhc3FwMnJiYjIgYVFBYzMjY1A0L+fuWMiuJ+cc6EknExfsxOrH6iS+6xtE6PASB7Tn6LjW5viQUX/vf+b1Km/vmSfuKIled9W6l6h21yUirDMod4bf0ZEjA4qJV+qMitAAMAQwCTBDcEzAADAA0AGQBXsgQaGxESObAEELAA0LAEELAR0ACwAy+xAAGwCitYIdgb9FmwAxCwCbAKK1jYG9xZsQQNsAorWCHYG/RZsAAQsBGwCitY2BvcWbEXDbAKK1gh2Bv0WTAxASE1IQEyFhQGIyImNDYDNDYzMhYVFAYjIiYEN/wMA/T+CURKSkRDSkpKSkNESkpEQ0oCRtQBskxyS0tyTPxKOkxMOjlKSgAAAwBP/3cEPQS7ABUAHQAlAGiyBCYnERI5sAQQsBvQsAQQsCPQALAARViwBC8bsQQcPlmwAEVYsA8vG7EPED5ZshgEDxESObIgBA8REjmwIBCwGdCwBBCxGwGwCitYIdgb9FmwGBCwIdCwDxCxIwGwCitYIdgb9FkwMRM0NjYzMhc3MwcWERQGBiMiJwcjNyYTFBcBJiMiBgU0JwEWMzI2T37klGpYR5FmxHvlll1aSJFmzvNAASsvOXeMAgk6/tgrM3uJAief/4kij9CZ/sCg/Ioek8+WATacYgJhFr2nlF39pxHAAAACAIL+YAQ3BgAADwAaAGayExscERI5sBMQsAzQALAJL7AARViwDC8bsQwcPlmwAEVYsAYvG7EGEj5ZsABFWLADLxuxAxA+WbIFDAMREjmyCgwDERI5sAwQsRMBsAorWCHYG/RZsAMQsRgBsAorWCHYG/RZMDEBFAIjIicRIxEzETYzMhIRJzQmIyIHERYzMjYEN+PCsmvz82qwxePzg3aVQUKWdIMCEvf+0XX9/weg/dd3/tr++gWmunv+IH67AAACAE//7ASyBgAAFgAhAI+yHyIjERI5sB8QsBDQALATL7AARViwDC8bsQwcPlmwAEVYsAYvG7EGED5ZsABFWLACLxuxAhA+WbIvEwFdsg8TAV2yFgITERI5sBYvsQAHsAorWCHYG/RZsgQMBhESObIODAYREjmwD9CwFhCwEdCwBhCxGgGwCitYIdgb9FmwDBCxHwGwCitYIdgb9FkwMQEjESMnBiMiAhE0EjMyFzUjNTM1MxUzARQWMzI3ESYjIgYEsq/cDG22vuvow6xq+/vzr/yQf3WVRUOVdoAEyPs4cIQBMgEH+gEvePKqjo78nqW5hQHOgrsAAAIAHwAABZ0FsAATABcAbQCwAEVYsA8vG7EPID5ZsABFWLAILxuxCBA+WbIUCA8REjmwFC+yEBQPERI5sBAvsADQsBAQsRcHsAorWCHYG/RZsAPQsAgQsAXQsBQQsQcBsAorWCHYG/RZsBcQsArQsBAQsA3QsA8QsBLQMDEBMxUjESMRIREjESM1MxEzESERMwEhNSEFHn9//P11/Hx8/AKL/Px5Aov9dQSuovv0Aof9eQQMogEC/v4BAv2iugABAI8AAAGCBDoAAwAdALAARViwAi8bsQIcPlmwAEVYsAAvG7EAED5ZMDEhIxEzAYLz8wQ6AAABAI4AAARrBDoADABgALAARViwBC8bsQQcPlmwAEVYsAgvG7EIHD5ZsABFWLACLxuxAhA+WbAARViwCy8bsQsQPlmyBgIEERI5sAYvtB8GLwYCcbKPBgFdsQEBsAorWCHYG/RZsgoBBhESOTAxASMRIxEzETMBIQEBIQHvb/LyVQFQASz+YQG5/ssBrP5UBDr+UAGw/fP90wAAAQAiAAAENgWwAA0AXQCwAEVYsAwvG7EMID5ZsABFWLAGLxuxBhA+WbIBDAYREjmwAS+wANCwARCxAgewCitYIdgb9FmwA9CwBhCxBAGwCitYIdgb9FmwAxCwCNCwCdCwABCwC9CwCtAwMQE3FQcRIRUhEQc1NxEzAaHq6gKV/G6Cgv0DZ0eTR/32ygKHJ5MnApYAAAEAIQAAAi4GAAALAEsAsABFWLAKLxuxCiI+WbAARViwBC8bsQQQPlmyAQQKERI5sAEvsADQsAEQsQIHsAorWCHYG/RZsAPQsAbQsAfQsAAQsAnQsAjQMDEBNxUHESMRBzU3ETMBmpSU84aG8wN5NZI1/RkCkC+SLwLeAAABAJD+SwUJBbAAEwBosgYUFRESOQCwAEVYsAAvG7EAID5ZsABFWLAQLxuxECA+WbAARViwBC8bsQQSPlmwAEVYsAwvG7EMED5ZsABFWLAOLxuxDhA+WbAEELEJAbAKK1gh2Bv0WbINAAwREjmyEg4AERI5MDEBERQGIyInNxYzMjU1AREjETMBEQUJvqlGPA4oOnv9gfz8An8FsPoYt8YRxwy4MQQV++sFsPvsBBQAAAEAfv5LBAYETgAaAGOyFRscERI5ALAARViwAy8bsQMcPlmwAEVYsAAvG7EAHD5ZsABFWLAKLxuxChI+WbAARViwGC8bsRgQPlmyARgDERI5sAoQsQ8BsAorWCHYG/RZsAMQsRUBsAorWCHYG/RZMDEBFzYzMhYXERQGIyInNxYzMjURNCYjIgcRIxEBXA1zxLC1AbumRToOKDt8XWmRS/MEOpaq1tL9G7TCEcYMsALZeHBn/OAEOgACAGT/7ActBcQAFwAjAJayASQlERI5sAEQsBrQALAARViwDC8bsQwgPlmwAEVYsA4vG7EOID5ZsABFWLADLxuxAxA+WbAARViwAC8bsQAQPlmwDhCxEAGwCitYIdgb9FmyEgAOERI5sBIvsRUBsAorWCHYG/RZsAAQsRcBsAorWCHYG/RZsAMQsRgBsAorWCHYG/RZsAwQsR0BsAorWCHYG/RZMDEhIQYjIiQCJxE0EiQzMhchFSERIRUhESEFMjcRJiMiBgcRFBYHLfydp3mn/veUApEBC6h7pwNc/UwCVv2qArv7fWNocluhrwGyFJMBDaoBOqwBEpYUzP5uyP5AHA0EOA7PvP7KwdEAAwBb/+wG8gRPAB4AKgAyAJ6yGTM0ERI5sBkQsCTQsBkQsC7QALAARViwAy8bsQMcPlmwAEVYsAgvG7EIHD5ZsABFWLAXLxuxFxA+WbAARViwGy8bsRsQPlmyBQgXERI5si8XCBESObAvL7QfLy8vAnGyjC8BXbEMB7AKK1gh2Bv0WbAXELEQAbAKK1gh2Bv0WbIZCBcREjmwItCwAxCxKAGwCitYIdgb9FmwK9AwMRM0ADMyFzY2FzISFRUhFhYzMjY3FwYGIyInBiMiABEXFBYzMjY1NCYjIgYlIgYHITU0JlsBD+D5hkG3bdbu/VYLkXVZj0dPR81494yG9uP+8vKGeXeGh3h1iAPhVXgUAbVxAif4AS+xVF4B/v3siIueKjKeP0GurgEtAQIJqrq5wKa+urqJeRlvegABAIsAAAKVBhUADAAzsgMNDhESOQCwAEVYsAQvG7EEIj5ZsABFWLAALxuxABA+WbAEELEJAbAKK1gh2Bv0WTAxMxE0NjMyFwcmIyIVEYvCsD9ZGSoyowSctsMVuQu6+2gAAAIAUf/sBR4FxAAWAB4AXrIAHyAREjmwF9AAsABFWLAPLxuxDyA+WbAARViwAC8bsQAQPlmyBQ8AERI5sAUvsA8QsQgBsAorWCHYG/RZsAAQsRcBsAorWCHYG/RZsAUQsRoBsAorWCHYG/RZMDEFIAARNSEmJiMiBwcnNzYzIAARFRQCBCcyNjchFRQWArj+3P69A9AF38ynlzQxIbDaAToBa6L+5amWvhL9L7oUAWABSYng8DQTxg9I/ov+t2vD/sOv1Nq9H7m/AAAB/+T+SwLTBhUAHgB0shQfIBESOQCwAEVYsBUvG7EVIj5ZsABFWLAQLxuxEBw+WbAARViwHS8bsR0cPlmwAEVYsAUvG7EFEj5ZsB0QsQABsAorWCHYG/RZsAUQsQsBsAorWCHYG/RZsAAQsA7QsA/QsBUQsRoBsAorWCHYG/RZMDEBIxEUBiMiJzcWFjMyNREjNTM1NDYzMhcHJiMiBxUzAoTJtaRINg8HRBJ4paXCsT1bGSY7nQHJA4b8NbDAEb8DCq4DyrRitsMVvAqtZwAAAgBY/+wFqgYuABgAJgBesgQnKBESObAEELAj0ACwAEVYsA0vG7ENID5ZsABFWLAELxuxBBA+WbIPDQQREjmwDy+xFgiwCitYIdgb9FmwDRCxHAGwCitYIdgb9FmwBBCxIwGwCitYIdgb9FkwMQEUAgQjIiQCJzU0EiQzMhc2NjUzFAYHFhcHNCYjIgIHFRQSMzISNQUQlP7ttLD+65cBlwETsf+iT0y7eXxXBP24qKS5ArmoqbUCstb+va2tAUDRUtUBRq2oDYOCpNEjp98S9v7+/+tU7P72AQD2AAIAT//sBLsEqAAXACIAXrIUIyQREjmwFBCwINAAsABFWLAELxuxBBw+WbAARViwFC8bsRQQPlmyBgQUERI5sAYvsQ0IsAorWCHYG/RZsBQQsRoBsAorWCHYG/RZsAQQsSABsAorWCHYG/RZMDETNDY2MzIXNjY1MxQGBxYXFRQGBiMiABEXFBYyNjU0JiMiBk995JThijUwp1hnPwJ755Xj/uzyivaJjXl3jAInof2JlRNqcoazJX2eHaD8igEuAQEJp73Auae9vQABAH3/7AY9BgEAGABWsgwZGhESOQCwAEVYsBgvG7EYID5ZsABFWLARLxuxESA+WbAARViwDC8bsQwQPlmyAQwYERI5sAEvsQgIsAorWCHYG/RZsAwQsRUBsAorWCHYG/RZMDEBFTY2NTMUBgcRFAAjIgA1ETMRFBYzIBERBL1tXrW7xf7X9/r+2vyUkAEkBbDcCoKh5NYJ/aXo/vEBC+0DzPwykpoBNAPGAAEAd//sBSgEkwAZAGOyBxobERI5ALAARViwDS8bsQ0cPlmwAEVYsAgvG7EIED5ZsABFWLAELxuxBBA+WbANELAT0LIVEwgREjmwFS+xAwiwCitYIdgb9FmyBhUIERI5sAgQsRABsAorWCHYG/RZMDEBFAYHESMnBiMiJjURMxEUMzI3ETMVNjY3NwUoj6LlBmvFsLXzq7E+80hBBQIEk7KlC/zPan7OwwK9/UbOfwMJiAdCTEwAAf+1/ksBkwQ6AAwAMLIDDQ4REjkAsABFWLAMLxuxDBw+WbAARViwBC8bsQQSPlmxCQGwCitYIdgb9FkwMQERBgYjIic3FjMyNREBkwG4p0Y4Dyc6fAQ6+4WywhG/DcAEbAACAFn/7AP4BE8AFgAeAGGyCB8gERI5sAgQsBfQALAARViwAC8bsQAcPlmwAEVYsAgvG7EIED5ZsgwACBESObAML7AAELEQAbAKK1gh2Bv0WbAIELEXAbAKK1gh2Bv0WbAMELEaB7AKK1gh2Bv0WTAxATIAFRUUBgYnIgI1NSEmJiMiBgcnNjYTMjY3IRUUFgIA5AEUe9qG1e8CqguPd1aLTk9G0pFWeBP+S3EET/7U9h+a+40BAQHtiIihJzWePkP8YI50GW96AAEAlATgA0MGAQAIAEUAsAQvsg8EAV2yUAQBXbJwBAFdsALQsAIvsAHQGbABLxiwBBCwB9CwBy+0DwcfBwJdsgMHBBESObABELAF0BmwBS8YMDEBFSMnByM1ATMDQ8OWlcEBD48E6wucnA0BFAAAAQByBOADNAYBAAgAJQCwBC+yDwQBXbAB0LABL7QPAR8BAl2yAAQBERI5sAjQsAgvMDEBNzMVASMBNTMB0pLQ/umW/uvOBWabCv7pARgJAP//AJsFDANKBaoABgBwAAAAAQB1BMwC+wXmAAsAMACwAy+yDwMBXbAG0LAGL7QPBh8GAl2wAxCxCAKwCitYIdgb9FmwBhCwC9CwCy8wMQEUBiAmNTMUFjI2NQL7sP7asLZLhEoF5n6cnH5CSUlCAAEAgQTfAYcF1QAJAB6yAwoLERI5ALAIL7IPCAFdsQIFsAorWCHYG/RZMDETNDYyFhUUBiImgUR+RER+RAVZNUdHNTRGRgACAHgEjQIzBioACQAUACwAsAUvsg8FAV2wE9CwEy+xAAqwCitYIdgb9FmwBRCxDQqwCitYIdgb9FkwMQEyFhQGIyImNDYHFBYzMjY1NCYiBgFWXYB9YGF9fxFCLi9BP2I/Bip7qnh4qnvQL0FAMC5DQwABACn+UgGhADwADwAjsg8QERESOQCwAEVYsAovG7EKEj5ZsQUDsAorWCHYG/RZMDEhBgYVFDMyNxcGIyImNTQ3AYxXSkcsLhVJXF909DheMUQXjixuW7VsAAABAHoE2wNXBfUAFQBCALADL7AI0LAIL7YPCB8ILwgDXbADELAL0LALL7AIELEPA7AKK1gh2Bv0WbADELESA7AKK1gh2Bv0WbAPELAV0DAxARQGIyIuAiMiBhUnNDYzMhYzMjY1A1d/YCc5aSsaJjWVf185oTQmNgXpbpIRPAw5Lghullo5LwAAAgBJBNEDVgX/AAMABwBAALACL7IPAgFdsADQsAAvtA8AHwACXbACELAD0BmwAy8YsAAQsAXQsAUvsAIQsAbQsAYvsAMQsAfQGbAHLxgwMQEzASMDMwMjAmju/vbFkOneuQX//tIBLv7SAAIAgv5qAez/vgALABcAPwCwGC+wA9CwAy9ADwADEAMgAzADQANQA2ADB12wD9CwDy+xCQmwCitYIdgb9FmwAxCxFQmwCitYIdgb9FkwMRc0NjMyFhUUBiMiJjcUFjMyNjU0JiMiBoJpTklqaklOaWUwIiEtLSEiMO5JY2FLSl5gSCEuLSIkMDAAAAH8jgTR/mYGAAADACMAsAEvsg8BAV2wANAZsAAvGLABELAC0LACL7QPAh8CAl0wMQEjASH+Zsr+8gEVBNEBLwAB/V4E0f82BgAAAwAjALACL7IPAgFdsAHQsAEvtA8BHwECXbACELAD0BmwAy8YMDEBIQEj/iEBFf7rwwYA/tH///xzBNv/UAX1AAcApfv5AAAAAf0+BOb+mQZ/AA4AKwCwAC+wBtCwBi+yHwYBXbIBAAYREjmxBwiwCitYIdgb9FmyDQEAERI5MDEBJzY2NTQjNzIWFRQGBxX9UQdJQZYHqatOSATmkgUcI0h7aFg8TgpFAAAC/AwE5P80Be4AAwAHADcAsAEvsADQGbAALxiwARCwBdCwBS+wBtCwBi+2DwYfBi8GA12wA9CwAy+wABCwBNAZsAQvGDAxASMBIQEjAzP+B9D+1QEGAiLD9foE5AEK/vYBCgAAAf0c/pT+L/+LAAgAEgCwAi+xBgWwCitYIdgb9FkwMQU0NjIWFAYiJv0cR4RISIRH8TVHR2pGRgABAMYE6QHiBkEAAwAXALACL7AA0LAAL7ACELAD0BmwAy8YMDEBMwMjAQPfjJAGQf6oAAMAZwTfA7oGrwADAAwAFQA8ALAUL7AC0LACL7AB0LABL7QPAR8BAl2wAhCwA9AZsAMvGLAUELAL0LALL7EGBbAKK1gh2Bv0WbAP0DAxATMDIwU0NjIWFAYiJiU0NjIWFAYiJgHu5YKS/qhEdkNDdkQCVkN2RER2Qwav/tYvMkREZEREMTJERGRERAD//wCOAkUBqQNSAgYAeAAAAAEAmwAABDcFsAAFACwAsABFWLAELxuxBCA+WbAARViwAi8bsQIQPlmwBBCxAAGwCitYIdgb9FkwMQEhESMRIQQ3/WD8A5wE5PscBbAAAAIAGQAABaAFsAADAAYAMACwAEVYsAAvG7EAID5ZsABFWLACLxuxAhA+WbEEAbAKK1gh2Bv0WbIGAgAREjkwMQEzASElIQECb/MCPvp5AVUC4P6YBbD6UMoDuwAAAwBb/+wFEwXEAAMAFAAiAHmyCCMkERI5sAgQsAHQsAgQsB/QALAARViwEC8bsRAgPlmwAEVYsAgvG7EIED5ZsgIIEBESOXywAi8YtGACcAICXbQwAkACAl2yAAIBcbEBAbAKK1gh2Bv0WbAQELEYAbAKK1gh2Bv0WbAIELEfAbAKK1gh2Bv0WTAxASE1IQUUAgQjIiQCJzU0EiQgBBIXBzQCIyICBxUUEjMyEjUDo/5AAcABcJT+7bOw/u6ZA5YBFAFkAROWAfy3qaS5ArumqbUCecKJ1v69raoBPM1d1QFEr6v+v9UF7wEF/v/rVPD++gEA9gAAAQAgAAAFEgWwAAYAMQCwAEVYsAMvG7EDID5ZsABFWLABLxuxARA+WbAARViwBS8bsQUQPlmyAAMBERI5MDEBASEBMwEhApj+l/7xAf71Af/+8ARE+7wFsPpQAAADAGwAAAQuBbAAAwAHAAsATgCwAEVYsAgvG7EIID5ZsABFWLACLxuxAhA+WbEAAbAKK1gh2Bv0WbIFCAIREjmwBS+xBgGwCitYIdgb9FmwCBCxCgGwCitYIdgb9FkwMTchFSETIRUhAyEVIWwDwvw+ZAL2/QpXA5n8Z8rKA03GAynMAAABAJsAAAUUBbAABwA5ALAARViwBi8bsQYgPlmwAEVYsAAvG7EAED5ZsABFWLAELxuxBBA+WbAGELECAbAKK1gh2Bv0WTAxISMRIREjESEFFPz9f/wEeQTk+xwFsAAAAQBHAAAETQWwAAwAPgCwAEVYsAgvG7EIID5ZsABFWLADLxuxAxA+WbEBAbAKK1gh2Bv0WbAF0LAIELEKAbAKK1gh2Bv0WbAH0DAxAQEhFSE1AQE1IRUhAQMc/nUCvPv6Acn+NwPi/WsBiALQ/frKlwJCAj+YzP3/AAADAEoAAAWuBbAAFAAbACIAbrIJIyQREjmwCRCwGNCwCRCwH9AAsABFWLATLxuxEyA+WbAARViwCC8bsQgQPlmyEhMIERI5sBIvsADQsiATCBESObAgL7EHAbAKK1gh2Bv0WbAK0LAgELAY0LASELEZAbAKK1gh2Bv0WbAf0DAxARYEFhAGBAcVIzUmJCY1NDYkNzUzARQWFxEGBgU0JicRNjYDfKMBBIuM/v6k/aj+/ouOAQKl/f3GoJ2bogN0oZmcngT+BI/7/sL3jQWpqQSM95+g/o0Esv0fnLAGAq4Ftp+etQb9UwexAAABAEQAAAVcBbAAFwBdsgAYGRESOQCwAEVYsBEvG7ERID5ZsABFWLAWLxuxFiA+WbAARViwBC8bsQQgPlmwAEVYsAsvG7ELED5ZshULFhESObAVL7AA0LAVELEMAbAKK1gh2Bv0WbAJ0DAxATY2NREzEQYABxEjESYAJxEzERYWFxEzA0yDkP0D/un2/PD+6AT8AY+A/AJDF76nAfH+Bvb+zxn+igF1FwEw9QH//gudwhgDbAABAGsAAATdBcMAJQBesgcmJxESOQCwAEVYsBovG7EaID5ZsABFWLAPLxuxDxA+WbAARViwJC8bsSQQPlmwDxCxEQGwCitYIdgb9FmwDtCwANCwGhCxBwGwCitYIdgb9FmwERCwItCwI9AwMSU2Ejc1NCYjIgYVFRQSFxUhNTMmAjU1NBIkMzIEEhUVFAIHMxUhAt90ewGdkI6bf3f+B9hreI4BBaSlAQaQd2vU/hDPIAEQ523K2tnNZOv+6x7Py2cBH55itgEdn57+4rVll/7cZ8sAAAIAVv/rBHkETgAWACEAfLIfIiMREjmwHxCwE9AAsABFWLATLxuxExw+WbAARViwAC8bsQAcPlmwAEVYsAwvG7EMED5ZsABFWLAILxuxCBA+WbEDAbAKK1gh2Bv0WbIKEwwREjmyFRMMERI5sAwQsRoBsAorWCHYG/RZsBMQsR8BsAorWCHYG/RZMDEBERYzMjcXBiMiJwYjIgI1NRASMzIXNwEUFjMyNxEmIyIGA/0DRhEKGDNMojVmwcPj5MS1ZxP+HHp2jEZGinN/BDr8+nsEtB6jogEd+A0BCgE2l4P9v56tiAHHjsUAAAIAlv53BGoFxAAUACgAaLInKSoREjmwJxCwANAAsA8vsABFWLAALxuxACA+WbAARViwDC8bsQwQPlmyJwAMERI5sCcvsSQBsAorWCHYG/RZsgYkJxESObAAELEYAbAKK1gh2Bv0WbAMELEeAbAKK1gh2Bv0WTAxATIWFRQGBxYWFRQGIyInESMRNDY2ATQmIyIGFREWMzI2NTQmJyM1MzICac/yY1h5gvLRpXryfNkBTHFdYIFYnXGJemd7SNQFxNiyX5swLL2CzexT/jgFqXPBcP5tWnZ+aPzlUolubZEBuQABACD+XwP1BDoACAA4sgAJChESOQCwAEVYsAEvG7EBHD5ZsABFWLAHLxuxBxw+WbAARViwBC8bsQQSPlmyAAcEERI5MDEBEzMBESMRATMCDuz7/o/z/o/7ATsC//vw/jUB0AQLAAACAFT/7AQ4BiAAHwArAGWyFiwtERI5sBYQsCPQALAARViwAy8bsQMiPlmwAEVYsBYvG7EWED5ZsAMQsQkBsAorWCHYG/RZsg4WAxESObAOL7EpAbAKK1gh2Bv0WbIdKQ4REjmwFhCxIwGwCitYIdgb9FkwMRM0NjMyFhcVJiMiBhUUFxYSFxUUBgYjIgARNDY3JyYmExQWMzI2NTQmJyIG0NS3SXFPl2lOWrzg3gJ64ZXi/u64iQJbaHaJeXeHkW15iQTqkaUWG8M1PTRdQk/+6swcm/aHASMBA6X/IgUoif19ory8tnjLF74AAAEAYP/sBAwETQAnAI6yFigpERI5ALAARViwCS8bsQkcPlmwAEVYsCUvG7ElED5ZshcJJRESOXywFy8YtEAXUBcCXbTQF+AXAl2xGAewCitYIdgb9FmyAxgXERI5sAkQsRABsAorWCHYG/RZsg0XEBESObIcDQFdsgsNAV2wJRCxHgGwCitYIdgb9FmyIR4YERI5tAQhFCECXTAxEzQ2NyYmNTQ2MzIWFSM0JiMiBhUUFjMzFSMGFRQWMzI2NTMUBCMiJGBpYldh+NK///J6WV5yYGnH0dJ9ZmKC8v78y9X++AEyXH8gJHlIlqW1kTxPTT88S60Dkz9XWUKburIAAQBh/n4DygWwAB4ATLIIHyAREjkAsA8vsABFWLAALxuxACA+WbAARViwFS8bsRUQPlmwABCxHAGwCitYIdgb9FmyARwAERI5sBUQsQgBsAorWCHYG/RZMDEBFQEGBhUUFhcXFhYVFAYHJzY1NicnJicmNRABNyE1A8r+YFZGPUvdYU96Un1dAm5oxEo5ASXc/cQFsJH+Cm26a1RaGEIfYlFHuj5lZ0Y9IRsyaVCLASABUf3DAAABAH7+YQQGBE4AEQBUsgwSExESOQCwAEVYsAMvG7EDHD5ZsABFWLAALxuxABw+WbAARViwBy8bsQcSPlmwAEVYsA8vG7EPED5ZsgEDDxESObADELEMAbAKK1gh2Bv0WTAxARc2MzIWFxEjETQmIyIHESMRAVwMd8G2rQPzXmiWRvMEOoOXxMX7nARTbml6/O8EOgAAAwBz/+wELAXEAA0AFgAeAHyyAx8gERI5sAMQsBPQsAMQsBvQALAARViwCi8bsQogPlmwAEVYsAMvG7EDED5Zsg4DChESOXywDi8YtGAOcA4CXbQwDkAOAl2yAA4BcbAKELETAbAKK1gh2Bv0WbAOELEYAbAKK1gh2Bv0WbADELEbAbAKK1gh2Bv0WTAxARACIyICAzUQEjMyEhMFITU0JiMiBhUFIRUUFjI2NwQs+OPf+gX25uL2Bf06AdR6cW96AdT+LHvgdwICcv7E/rYBQQEt6QE1AUz+xP7TIzDOy8vO7yrQ0crKAAEAqf/0AmEEOgAMACkAsABFWLAALxuxABw+WbAARViwCS8bsQkQPlmxBAGwCitYIdgb9FkwMQERFBYzMjcVBiMgEREBnDI+KitKVv7oBDr89j02CrwXATUDEQAAAQAW/+4ESgX7ABkAUrIDGhsREjkAsAAvsABFWLALLxuxCxA+WbAARViwEC8bsRAQPlmwCxCxBwGwCitYIdgb9FmyDwALERI5sA8QsBLQsAAQsRUBsAorWCHYG/RZMDEBMhYXARYXFzcXBiMiJicDAyEBJyYnIwcnNgESbHgfAaskMSARBCo0bXUryvb+9wGBWyJJIhsDOwX7VVD7v1YHAQHAClhvAhT9NwQP2ksDArYQAAEAZP52A9QFxAAsAFmyAy0uERI5ALAWL7AARViwKi8bsSogPlmxAgGwCitYIdgb9FmyCC0qERI5sAgvsQkBsAorWCHYG/RZsh0tKhESObAdELEOAbAKK1gh2Bv0WbIkCQgREjkwMQEmIyIGFRQhMxUjIBEUFgQWFxYVBgYHJzY2NTQmJCcmJjU0NjcmJjU0JDMyFwODild6iAEciYz+noEBGW8jUQJ7UIM1Lj/+/Ux/dqOQbnwBAuOZfQTaJFZLuMb+42KIQiUYOG1IuztkOVApIy1EIDW3lJHELSiOYabFLAABAC3/9ATPBDoAFABesgsVFhESOQCwAEVYsBMvG7ETHD5ZsABFWLAKLxuxChA+WbAARViwDy8bsQ8QPlmwExCxAAewCitYIdgb9FmwChCxBQGwCitYIdgb9FmwABCwDdCwDtCwEdCwEtAwMQEjERQWMzI3FQYjIBERIREjESM1IQSpnzE/Ji9KVv7o/rTzqwR8A3z9tj43CrwXATUCU/yEA3y+AAIAgP5gBDEETgAOABoAWbIRGxwREjmwERCwANAAsABFWLAALxuxABw+WbAARViwCi8bsQoSPlmwAEVYsAcvG7EHED5ZsgkABxESObERAbAKK1gh2Bv0WbAAELEXAbAKK1gh2Bv0WTAxATISERUUAiMiJxEjETQAAxYzMjY1NCYjIgYVAlbg++DBs2rzAQMQQ5V2fXxyZncETv7L/u8P8v7ld/39A9vyASH81XWts7jFwaAAAAEAUv6KA+kETgAiAE+yGyMkERI5ALAARViwAC8bsQAcPlmwAEVYsBQvG7EUGD5ZsAAQsATQsAAQsQcBsAorWCHYG/RZshwjABESObAcELENAbAKK1gh2Bv0WTAxATIWFSM0JiMiBhUVFBYEFhYXFAYHJzY2NTQmJyYmJzU0NjYCOMTt5G1gcYOUAS5gMQF/TH8zKjxB7u0BeNwETt27YXS8qhqDm1Y5U0JIvzhlN04sKCoPN/7RJ536iQAAAgBS/+wEfgQ6AA8AGwBOsgccHRESObAHELAT0ACwAEVYsA4vG7EOHD5ZsABFWLAHLxuxBxA+WbAOELEAAbAKK1gh2Bv0WbAHELETAbAKK1gh2Bv0WbAAELAZ0DAxASEWFRQGBiMiABE1NAA3IQEUFjMyNjU0JiMiBgR+/vW6et6R4v7wAQzfAkH8x4V6dYGDdXaHA3aS+47sgwEsAQMM7gEjAv3Yqbu8vZyzsAAAAQA//+wD7AQ6ABAAS7IBERIREjkAsABFWLAPLxuxDxw+WbAARViwCi8bsQoQPlmwDxCxAAGwCitYIdgb9FmwChCxBQGwCitYIdgb9FmwABCwDdCwDtAwMQEhERQWMzI3FwYjIAMRITUhA+z+mCszJzcmUGz+7AX+rgOtA3n9sDs7FrEsATkCVMEAAQCA/+sECAQ6ABIAObIOExQREjkAsABFWLAALxuxABw+WbAARViwDi8bsQ4QPlmxAwGwCitYIdgb9FmwABCwCNCwCC8wMQEREDMyNjUmAzMWERAAIyImJxEBcqFxkQNu8XP+/OfL0QEEOv12/v3poOcBHeb+4v70/sHi2AKVAAACAET+IgWFBEEAGgAjAGGyECQlERI5sBAQsBvQALAZL7AARViwES8bsREcPlmwAEVYsAYvG7EGHD5ZsABFWLAALxuxABA+WbENAbAKK1gh2Bv0WbAAELAY0LANELAb0LARELEhAbAKK1gh2Bv0WTAxBSQANTQSNxcGBgcUFhcRNDYzMhYWFRQABREjEzY2NSYmIyIVAmX+/P7jfnOYSEwCmpSefJPsh/7e/vXz85WlAo10Nw4cATf/pAEFU5JGvGihzR4CgHeSjfuS8/7XGv4xApQZwZeXvz4AAAEAT/4iBX4EOgAYAEWyABkaERI5ALANL7AARViwFC8bsRQcPlmwAEVYsA8vG7EPED5ZsRcBsAorWCHYG/RZsAHQsBQQsBjQsAbQsA8QsAzQMDEBETY2NSYDMxYREAAFESMRJAADETMREAURA1KTpwVw7nn+4f7z8/78/vUB8wEdBDr8fRvOpOIBFOP+7f78/soa/jIB0B4BMwEKAe3+GP6iPAOCAAABAGb/7AYtBDoAIABXshohIhESOQCwAEVYsAAvG7EAHD5ZsABFWLAYLxuxGBA+WbAARViwHC8bsRwQPlmxBQGwCitYIdgb9FmyCQAcERI5sA7QsAAQsBPQsBMvshoFGBESOTAxAQIHFBYzMjY1ETMRFhYzMjY1JgMzFhACIyInBiMiAhA3AeWGB2FYW2D7Al9aWGEHhfGN1cvoXFzmy9aNBDr+6e29y52UAUb+r46Yy73vARXo/cj+0t7eAS4COOgAAAIAdv/sBJgFxAAgACkAbrIPKisREjmwDxCwIdAAsABFWLAaLxuxGiA+WbAARViwBi8bsQYQPlmyJBoGERI5sCQvsRMBsAorWCHYG/RZsALQsgsaBhESObAGELEPAbAKK1gh2Bv0WbAkELAe0LAaELEnAbAKK1gh2Bv0WTAxAQYHFRQGIyIANRE3ERQWMzI2NTUmACc1NDYzMhYVETY3ARQWFxEmIyIGBJg6RPrV0/7+7IJuYm3R/wADxaWnvEsq/ap9awRtNEMCVxQLddr9AQXUAR0C/t59j4aDfCYBE8AbqczQu/7ODAsBI2yiIAFFmkkAAf/hAAAEngXDABoAQ7IAGxwREjkAsABFWLAELxuxBCA+WbAARViwDS8bsQ0QPlmyAAQNERI5sAQQsQkBsAorWCHYG/RZsBLQsAQQsBfQMDEBEzY2MzIXByYjIgcBESMRASYjIgcnNjMyFhcCP9IremBGQiYNKEEf/tn8/tshQCsKJDxKZ30sAwcB+GRgGsIFRf1r/e4CEAKXRQXBG2RsAAIAM//sBlQEOgASACYAcrIIJygREjmwCBCwHtAAsABFWLARLxuxERw+WbAARViwBi8bsQYQPlmwAEVYsAovG7EKED5ZsBEQsQABsAorWCHYG/RZsggRBhESObAP0LAQ0LAV0LAW0LAKELEbAbAKK1gh2Bv0WbIfEAoREjmwJNAwMQEjFhUQAiMiJwYjIgIRNDcjNSEBJichBgcUFjMyNjc1MxUWFjMyNgZUgDfKvO5cXO69yDZvBiH+xQQ9/MY8BFNLXGYB+gJjXUtTA4Oer/7i/tTi4gEuARyxnLf9/KCtsZy+ypeV6O6Pl8oAAQAi//IFvAWwABgAcbIRGRoREjkAsABFWLAXLxuxFyA+WbAARViwCS8bsQkQPlmwAEVYsBMvG7ETED5ZsBcQsQABsAorWCHYG/RZsgQXCRESObAEL7AJELEKAbAKK1gh2Bv0WbAEELEQAbAKK1gh2Bv0WbAAELAV0LAW0DAxASERNjMyBBAEIycyNjUmJiMiBxEjESE1IQSQ/hOUcvsBGP7u/gGJjAGPj4Z4/f58BG4E5P50JvD+UOy/eYR3hyD9dATkzAAAAQBo/+wE7wXEAB8AdLIDICEREjkAsABFWLAMLxuxDCA+WbAARViwAy8bsQMQPlmwDBCxEwGwCitYIdgb9FmyFwwDERI5fLAXLxi0MBdAFwJdtGAXcBcCXbTQF+AXAl2yABcBcbEYAbAKK1gh2Bv0WbADELEcAbAKK1gh2Bv0WTAxAQYAIyIkAic1NBIkMzIAFyMmJiMiBgchFSEWFjMyNjcE7hb+1Piv/vWRAZIBEbTzASUY/BKUjqGwCAH7/gQHq52TlhQB2ej++6UBNs97zwE6qv727JyO5dLK3eWHnQACAC0AAAhBBbAAGQAiAHeyCSMkERI5sAkQsBrQALAARViwGC8bsRggPlmwAEVYsAgvG7EIED5ZsABFWLAQLxuxEBA+WbIAGAgREjmwAC+wGBCxCgGwCitYIdgb9FmwEBCxEgGwCitYIdgb9FmwABCxGgGwCitYIdgb9FmwEhCwG9CwHNAwMQEhHgIVFAQHIREhAwICBiMjNTc+AjcTIRERITI2NTQmJwUNATGZ63/+6+X9yv5CGg9jvJ5AKFdfMQocA6sBKX6Rj3oDoQF11IfO/QUE5P3N/vj+3YbKAwhq19ECyf0m/fSTdXOPAgAAAgCbAAAIRwWwABMAHACKsgEdHhESObABELAU0ACwAEVYsAIvG7ECID5ZsABFWLATLxuxEyA+WbAARViwEC8bsRAQPlmwAEVYsA0vG7ENED5ZsgAQExESObAAL7KfAAFdsgQNAhESObAEL7AAELEPAbAKK1gh2Bv0WbAEELEUAbAKK1gh2Bv0WbANELEVAbAKK1gh2Bv0WTAxASERMxEhMhYWFRQEIyERIREjETMBESEyNjU0JiMBlwKA/AErnO5//uPz/eD9gPz8A3wBKX6SlHwDRQJr/dJuy4XN9wJ6/YYFsP0I/hiGcG+DAAABADEAAAXIBbAAFQBYALAARViwFC8bsRQgPlmwAEVYsAgvG7EIED5ZsABFWLAQLxuxEBA+WbAUELEAAbAKK1gh2Bv0WbIEEBQREjmwBC+xDQGwCitYIdgb9FmwABCwEtCwE9AwMQEhETYzIAQVESMRNCYjIgcRIxEhNSEEkv4Rg48BDAEH/H2ajIb8/ooEYQTk/psb7OX+NwHKi3oc/U0E5MwAAAEAkv6YBQ0FsAALAEkAsAkvsABFWLAALxuxACA+WbAARViwBC8bsQQgPlmwAEVYsAYvG7EGED5ZsABFWLAKLxuxChA+WbECAbAKK1gh2Bv0WbAD0DAxEzMRIREzESERIxEhkv0Cgf3+S/3+NwWw+xoE5vpQ/pgBaAAAAgCQAAAEwQWwAA0AFgBeshAXGBESObAQELAD0ACwAEVYsAwvG7EMID5ZsABFWLAKLxuxChA+WbAMELEAAbAKK1gh2Bv0WbICDAoREjmwAi+xDgGwCitYIdgb9FmwChCxDwGwCitYIdgb9FkwMQEhESEyFhYVFAQHIREhAREhMjY1NCYnBCz9YQEqoO58/uvv/dMDnP1hASmAj4x8BOT+n27Khcz4AgWw/Qj+EotzboACAAIAJP6aBdwFsAAOABQAZ7ISFRYREjmwEhCwC9AAsABFWLALLxuxCyA+WbAARViwBC8bsQQYPlmwAEVYsAIvG7ECED5ZsAQQsAHQsAIQsQYBsAorWCHYG/RZsA3QsA7QsA/QsBDQsAsQsREBsAorWCHYG/RZMDEBIxEhESMDMzYSNxMhETMhIREhAwIFz/D8QfQIdVdoDyYDlrn72wJw/lcYG/6aAWb+mgIwVAFBywKG+xoEGv5m/mUAAAEAFgAAB5sFsAAVAH4AsABFWLAJLxuxCSA+WbAARViwDS8bsQ0gPlmwAEVYsBEvG7ERID5ZsABFWLACLxuxAhA+WbAARViwBi8bsQYQPlmwAEVYsBQvG7EUED5ZshAJAhESObAQL7EAAbAKK1gh2Bv0WbAE0LIIEAAREjmwEBCwC9CyEwAQERI5MDEBIxEjESMBIQEBIQEzETMRMwEhAQEhBP+j/Kr+m/7FAdX+SgEyAVyd/JYBWQEx/k4B0f7GAnT9jAJ0/YwDBwKp/aACYP2gAmD9Wfz3AAEASf/tBH8FwwApAImyJSorERI5ALAARViwCy8bsQsgPlmwAEVYsBcvG7EXED5ZsAsQsQMBsAorWCHYG/RZsigLFxESOXywKC8YshAoAV20MChAKAJdtGAocCgCXbSgKLAoAl2yBigDERI5sSUBsAorWCHYG/RZshElKBESObAXELEfAbAKK1gh2Bv0WbIcJR8REjkwMQE0JiMiBhUjNDY2MzIEFRQGBxYWFRQEIyImJjUzFBYzMjY1NCYjIzUzIANslH9tkvyE6o36ARV4bHqB/tT6mvl9/Jx4hqOPiquiAQwEI2J0c1t3umfaxGOmMCqrf8Tnbr57XoF+ZXtvyAABAJQAAAUNBbAACQBFALAARViwAC8bsQAgPlmwAEVYsAcvG7EHID5ZsABFWLACLxuxAhA+WbAARViwBS8bsQUQPlmyBAACERI5sgkAAhESOTAxATMRIxEBIxEzEQQQ/f39gf39BbD6UAQN+/MFsPvyAAABAC0AAAUNBbAAEQBPsgQSExESOQCwAEVYsAAvG7EAID5ZsABFWLABLxuxARA+WbAARViwCS8bsQkQPlmwABCxAwGwCitYIdgb9FmwCRCxCwGwCitYIdgb9FkwMQERIxEhAwICBiMjNTc+AjcTBQ38/kIaD2O8nkAoV18xChwFsPpQBOT9zf74/t2GygMIatfRAskAAQA5/+sE3QWwAA8ASrIAEBEREjkAsABFWLAPLxuxDyA+WbAARViwBi8bsQYQPlmyAA8GERI5sA8QsAHQsAEvsAYQsQoBsAorWCHYG/RZsg0GDxESOTAxAQEhAQcGIyc3FjMyNzcBIQKgASQBGf4FLmTgaAIYPWwsNP4OARQCtwL5+0hbsgbIBFx7BCQAAAMAT//EBhgF7AAZACIAKwBdsgwsLRESObAMELAh0LAMELAj0ACwCy+wGC+yFhgLERI5sBYvsADQsiUYCxESObAlL7EJAbAKK1gh2Bv0WbAN0LAWELEaAbAKK1gh2Bv0WbAlELAg0LAaELAj0DAxATMyBBIVFAIEByMVIzUjIiQCNTQSJDMzNTMBIgYVFBYzMxEzETMyNjU0JiMDrhaoAROZmf7xqBrzGKn+7JeYARKqGPP+9ai9vKwV8xiou7urBSaX/u6rqv7xlgG+vpcBDqmrARKZxv5v0rm0zwMO/PLSs7fSAAEAkv6hBb0FsAALADwAsAkvsABFWLAALxuxACA+WbAARViwBC8bsQQgPlmwAEVYsAovG7EKED5ZsQIBsAorWCHYG/RZsAbQMDETMxEhETMRMwMjESGS/QKB/bAU6PvRBbD7GgTm+xz91QFfAAEAjgAABO4FsAARAEAAsABFWLAALxuxACA+WbAARViwCS8bsQkgPlmwAEVYsAEvG7EBED5Zsg4BCRESObAOL7EFAbAKK1gh2Bv0WTAxAREjEQYjICQnETMRFhYzMjcRBO78orD++/70AfwBfpeupAWw+lACPSnm6AHO/jCLdioCpwABAJgAAAcDBbAACwBJALAARViwAC8bsQAgPlmwAEVYsAMvG7EDID5ZsABFWLAHLxuxByA+WbAARViwCS8bsQkQPlmxAQGwCitYIdgb9FmwBdCwBtAwMQERIREzESERMxEhEQGWAbz8Abn8+ZUFsPsaBOb7GgTm+lAFsAAAAQCY/qIHrQWwAA8AVQCwCy+wAEVYsAAvG7EAID5ZsABFWLADLxuxAyA+WbAARViwBy8bsQcgPlmwAEVYsA0vG7ENED5ZsQEBsAorWCHYG/RZsAXQsAbQsAnQsArQsALQMDEBESERMxEhETMRMwMjESERAZYBvPwBufyqFN753QWw+xoE5vsaBOb7Ev3gAV4FsAACABgAAAXUBbAADQAWAGGyARcYERI5sAEQsA7QALAARViwAC8bsQAgPlmwAEVYsAovG7EKED5ZsgIAChESObACL7AAELEMAbAKK1gh2Bv0WbACELEOAbAKK1gh2Bv0WbAKELEPAbAKK1gh2Bv0WTAxEyERITIWFhUUBAchESEBESEyNjU0JicYAocBKqDuff7p7v3U/nUChwEpgI+MfAWw/dNuyYbN9wIE7f3L/hKLc26AAgADAJsAAAZYBbAACwAPABgAb7ICGRoREjmwAhCwDdCwAhCwF9AAsABFWLALLxuxCyA+WbAARViwDi8bsQ4gPlmwAEVYsAgvG7EIED5ZsABFWLAMLxuxDBA+WbIACAsREjmwAC+xEAGwCitYIdgb9FmwCBCxEQGwCitYIdgb9FkwMQEhMhYWFRQEByERMwEjETMBESEyNjU0JicBmAEqoO58/uvv/dP9BMD8/PtAASmAj4x8A4NuyoXM+AIFsPpQBbD9CP4Si3NugAIAAgCQAAAEwQWwAAsAFABPsg4VFhESObAOELAB0ACwAEVYsAsvG7ELID5ZsABFWLAJLxuxCRA+WbIACQsREjmwAC+xDAGwCitYIdgb9FmwCRCxDQGwCitYIdgb9FkwMQEhMhYWFRQEByERMxERITI2NTQmJwGNASqg7nz+6+/90/0BKYCPjHwDg27Khcz4AgWw/Qj+EotzboACAAEAa//sBPEFxAAfAIKyAyAhERI5ALAARViwEy8bsRMgPlmwAEVYsBwvG7EcED5ZsgkTHBESOXywCS8YtGAJcAkCXbTQCeAJAl20MAlACQJdsgAJAXGxBgGwCitYIdgb9FmwHBCxAwGwCitYIdgb9FmyAAYDERI5sBMQsQwBsAorWCHYG/RZsg8JDBESOTAxARYWMzI2NyE1ISYmIyIGByM2ADMyBBIXFRQCBCMiACcBaBSXk5yrBv3+AgIIsaCMlRL8GAEl8rMBEJMBj/70sPj+1BYB2Z6G5NfM2OSMnu4BCKj+yM17z/7HqAEF6AACAKD/7AcHBcQAFwAlAIGyEiYnERI5sBIQsB3QALAARViwEy8bsRMgPlmwAEVYsA0vG7ENID5ZsABFWLAELxuxBBA+WbAARViwCi8bsQoQPlmyDgoNERI5fLAOLxi0YA5wDgJdsQgBsAorWCHYG/RZsBMQsRsBsAorWCHYG/RZsAQQsSIBsAorWCHYG/RZMDEBFAIEIyIkAicjESMRMxEzNhIkMzIEEhcHNAIjIgIHFRQSMzISNQcHlP7ts6f++J4Otvz8swaaAQ+tsgETlgH9t6ikuQK7pqi1ArLW/r2tmAEcvf2jBbD9cckBNaWr/r/VBfIBAv7/61Tw/voBAPYAAgAgAAAEXwWwAAwAFQBjshAWFxESObAQELAK0ACwAEVYsAovG7EKID5ZsABFWLAALxuxABA+WbAARViwAy8bsQMQPlmyEQoAERI5sBEvsQEBsAorWCHYG/RZsgUBERESObAKELESAbAKK1gh2Bv0WTAxIREhASEBJhE0JDchEQEUFjMzESMiBgNi/ub+5/7xAUX+ARP2Ae/9BIqK6+uMiAIg/eACa3gBEdHpAvpQA+l7igIAhgACAFv/6wQ8BhMAGgAmAFayDicoERI5sA4QsBvQALAARViwES8bsREiPlmwAEVYsAcvG7EHED5ZsgARBxESObAAL7IZAAcREjmxGwGwCitYIdgb9FmwBxCxIQGwCitYIdgb9FkwMQEyEhUVFAAjIgARNRASNzY2NTMUBgYHBgYHNhciBhUUFjMyNjU0JgJ6zPb+9eXf/u749opRxEKIppifG5GTdoaEenmFhQP+/u/qDOr+3gEoAQBGAV4BmDMcPzZlfk8jIKSRlcOfpZyur7CMowADAI8AAAQ6BDoADgAVABwAe7ICHR4REjmwAhCwFdCwAhCwF9AAsABFWLABLxuxARw+WbAARViwAC8bsQAQPlmyFgEAERI5fLAWLxi0QBZQFgJdtNAW4BYCXbEPB7AKK1gh2Bv0WbIIDxYREjmwABCxEAGwCitYIdgb9FmwARCxGwGwCitYIdgb9FkwMTMRITIWFRQGBxYWFRQGIwERITI1NCMlMzI1NCcjjwG33uhdW2p839H++AEKu77++cjPxNMEOpuRS3cgFoZbl54Bzf7zhoeueoAEAAABAIUAAANNBDoABQAsALAARViwBC8bsQQcPlmwAEVYsAIvG7ECED5ZsAQQsQABsAorWCHYG/RZMDEBIREjESEDTf4q8gLIA3b8igQ6AAACACf+vgTFBDoADgAUAF2yEhUWERI5sBIQsATQALAML7AARViwBC8bsQQcPlmwAEVYsAovG7EKED5ZsQABsAorWCHYG/RZsAbQsAfQsAwQsAnQsAcQsA/QsBDQsAQQsREBsAorWCHYG/RZMDE3NjY3EyERMxEjESERIxMhIREhBwKBZUUHDgLvlvL9SvYBAXYBn/7vBw7CccueAZ78iP38AUL+vgIEAqfP/tYAAQAeAAAGXAQ6ABUAgwCwAEVYsAkvG7EJHD5ZsABFWLANLxuxDRw+WbAARViwES8bsREcPlmwAEVYsAIvG7ECED5ZsABFWLAGLxuxBhA+WbAARViwFC8bsRQQPlmyEBECERI5sBAvso8QAV2xAAGwCitYIdgb9FmwBNCyCBAAERI5sBAQsAvQshMAEBESOTAxASMRIxEjAyEBASETMxEzETMTIQEBIQQ1gfOA+f7WAWf+rAEp9XLzc/YBKf6tAWn+0gGz/k0Bs/5NAjMCB/5XAan+VwGp/fz9ygABAE3/7APEBE0AJwCQsh4oKRESOQCwAEVYsCUvG7ElHD5ZsABFWLAILxuxCBA+WbIZJQgREjl8sBkvGLRAGVAZAl200BngGQJdsRYHsAorWCHYG/RZsgMWGRESObAIELEQB7AKK1gh2Bv0WbINFhAREjm0Aw0TDQJdsCUQsR4HsAorWCHYG/RZsiEZHhESOUAJCyEbISshOyEEXTAxARQGBxYVFAYjIiYmNTMUFjMyNjU0JiMjNTM2NTQmIyIGFSM0NjMyFgOwV0+68st8zHLydlpZaVxgrrSjXlJQbvLwucngAxJIeSRBupWxU5lpQllTQ09GrwKEQkpPPI+3pAAAAQCGAAAEEgQ6AAkARQCwAEVYsAAvG7EAHD5ZsABFWLAHLxuxBxw+WbAARViwAi8bsQIQPlmwAEVYsAUvG7EFED5ZsgQHAhESObIJBwIREjkwMQEzESMRASMRMxEDIPLy/ljy8gQ6+8YC0v0uBDr9LgAAAQCPAAAEZQQ6AAwAaQCwAEVYsAQvG7EEHD5ZsABFWLAILxuxCBw+WbAARViwAi8bsQIQPlmwAEVYsAsvG7ELED5ZsgYCBBESOXywBi8YtNMG4wYCXbRDBlMGAl2yEwYBcbEBAbAKK1gh2Bv0WbIKAQYREjkwMQEjESMRMxEzASEBASEB/Xvz82sBKwEs/nkBqP7EAaz+VAQ6/lABsP36/cwAAQAhAAAEFAQ6AA8AT7IEEBEREjkAsABFWLAALxuxABw+WbAARViwAS8bsQEQPlmwAEVYsAgvG7EIED5ZsAAQsQMBsAorWCHYG/RZsAgQsQoBsAorWCHYG/RZMDEBESMRIQMCBiMjJzc2NjcTBBTz/s4UE6uwSwEyUEkKFAQ6+8YDdv6H/vDtygULreUBzgAAAQCPAAAFbwQ6AAwAWQCwAEVYsAEvG7EBHD5ZsABFWLALLxuxCxw+WbAARViwAy8bsQMQPlmwAEVYsAYvG7EGED5ZsABFWLAJLxuxCRA+WbIACwMREjmyBQsDERI5sggLAxESOTAxAQEhESMRASMBESMRIQL/AUABMPP+1qX+1fMBMgErAw/7xgLM/TQC0P0wBDoAAAEAhgAABBEEOgALAIYAsABFWLAGLxuxBhw+WbAARViwCi8bsQocPlmwAEVYsAAvG7EAED5ZsABFWLAELxuxBBA+WbIJCgAREjmwCS+0vwnPCQJdtF8JbwkCcbTvCf8JAnGyXwkBcrQvCT8JAnKyvwkBcbQfCS8JAnGyjwkBXbSPCZ8JAnKxAgGwCitYIdgb9FkwMSEjESERIxEzESERMwQR8/5b8/MBpfMBtf5LBDr+PQHDAAEAhgAABBIEOgAHADkAsABFWLAGLxuxBhw+WbAARViwAC8bsQAQPlmwAEVYsAQvG7EEED5ZsAYQsQIBsAorWCHYG/RZMDEhIxEhESMRIQQS8/5a8wOMA3b8igQ6AAABACMAAAPQBDoABwAyALAARViwBi8bsQYcPlmwAEVYsAIvG7ECED5ZsAYQsQABsAorWCHYG/RZsATQsAXQMDEBIREjESE1IQPQ/qHz/qUDrQN5/IcDecEAAwBU/mAFfwYAABoAJAAvAIGyBzAxERI5sAcQsCDQsAcQsCrQALAGL7AARViwAy8bsQMcPlmwAEVYsAovG7EKHD5ZsABFWLATLxuxExI+WbAARViwEC8bsRAQPlmwAEVYsBcvG7EXED5ZsAoQsR4BsAorWCHYG/RZsBAQsSMBsAorWCHYG/RZsCjQsB4QsC3QMDETEBIzMhcRMxE2MzISERQCIyInESMRBiMiAiclNCYjIgcRFjMyARQWMzI3ESYjIgZU0btMPvJAVrrT1LdTRfI9T6/RCQQ3dGotJSEz3Py6bGotISIqaHACDgEJATccAc7+LiD+y/7g8/7mHv5WAaYaAQPjPLbHDf06CgFLoqkKAskKwQABAIb+vwSlBDoACwA8ALAIL7AARViwAC8bsQAcPlmwAEVYsAQvG7EEHD5ZsABFWLAKLxuxChA+WbECAbAKK1gh2Bv0WbAG0DAxEzMRIREzETMDIxEhhvMBpvOTFN380gQ6/IgDePyI/f0BQQABAF8AAAPgBDsAEQBJsgQSExESOQCwAEVYsAkvG7EJHD5ZsABFWLAQLxuxEBw+WbAARViwAS8bsQEQPlmyDQEJERI5fLANLxixBAGwCitYIdgb9FkwMSEjEQYjIiY1ETMRFBYzMjcRMwPg815o3urzaWxiZPMBaRbVxwFM/rR2YhcCDAABAIYAAAYDBDoACwBJALAARViwAC8bsQAcPlmwAEVYsAMvG7EDHD5ZsABFWLAHLxuxBxw+WbAARViwCS8bsQkQPlmxAQGwCitYIdgb9FmwBdCwBtAwMQERIREzESERMxEhEQF5AVLzAVPy+oMEOvyIA3j8iAN4+8YEOgAAAQB+/r8GtAQ6AA8ATACwDC+wAEVYsAAvG7EAHD5ZsABFWLADLxuxAxw+WbAARViwBy8bsQccPlmwAEVYsA0vG7ENED5ZsQEBsAorWCHYG/RZsAXQsAnQMDEBESERMxEhETMRMwMjESERAXEBUvMBU/K5FN36uwQ6/IgDePyIA3j8iP39AUEEOgAAAgAfAAAE6gQ6AA0AFQBesgAWFxESObAO0ACwAEVYsAwvG7EMHD5ZsABFWLAILxuxCBA+WbIADAgREjmwAC+wDBCxCgGwCitYIdgb9FmwABCxDgGwCitYIdgb9FmwCBCxDwGwCitYIdgb9FkwMQEzMhYWFRQGByERITUhEREzMjY0JicCSu6FxmfsxP4d/sgCK+1ZZ2VWAuJcpm6nygEDdsT95f6jWaRfAQADAI8AAAXJBDoACwAPABcAb7IHGBkREjmwBxCwDdCwBxCwFNAAsABFWLAKLxuxChw+WbAARViwDi8bsQ4cPlmwAEVYsAgvG7EIED5ZsABFWLAMLxuxDBA+WbIADggREjmwAC+xEAGwCitYIdgb9FmwCBCxEQGwCitYIdgb9FkwMQEzMhYWFRQGByERMwEjETMBETMyNjQmJwGC7oXGZ+zE/h3zBEfz8/u57VlnZVYC4lymbqfKAQQ6+8YEOv3l/qNZpF8BAAACAI8AAAQiBDoACwATAE+yDhQVERI5sA4QsAHQALAARViwCi8bsQocPlmwAEVYsAgvG7EIED5ZsgAKCBESObAAL7EMAbAKK1gh2Bv0WbAIELENAbAKK1gh2Bv0WTAxATMyFhYVFAYHIREzEREzMjY0JicBgu6FxmfsxP4d8+1ZZ2VWAuJcpm6nygEEOv3l/qNZpF8BAAABAFH/7APoBE4AIACAshAhIhESOQCwAEVYsAgvG7EIHD5ZsABFWLAQLxuxEBA+WbAIELEAAbAKK1gh2Bv0WbIeCBAREjl8sB4vGLRAHlAeAl2yAx4AERI5shwDAV2yCwMBXbEbB7AKK1gh2Bv0WbAQELEYAbAKK1gh2Bv0WbIVGxgREjm0BBUUFQJdMDEBIgYVIzQ2NjMyABUVFAYGIyImJjUzFBYzMjY3ITUhJiYCAVV25XTKctwBC3nckXvIbuV2VmZ+DP6sAVMOfgOLaU9kr2j+0vwZm/yIZ7p1XXeZiaiEjwACAJH/7AY4BE4AFAAfAIiyFSAhERI5sBUQsA3QALAARViwBC8bsQQcPlmwAEVYsBMvG7ETHD5ZsABFWLARLxuxERA+WbAARViwDC8bsQwQPlmyARETERI5fLABLxi00AHgAQJdtEABUAECXbEPAbAKK1gh2Bv0WbAMELEXAbAKK1gh2Bv0WbAEELEdAbAKK1gh2Bv0WTAxATM2JDMyABcXFAYGIyIAJyMRIxEzARQWMjY1NCYjIgYBhMwbAQrL2wERCwF75ZbS/vMVyvPzAbmK9oiNeHeMAofP+P7m6Tmg/IoBBNT+PAQ6/dinvcC5p729AAIAJwAAA98EOgANABYAY7IUFxgREjmwFBCwBNAAsABFWLAALxuxABw+WbAARViwAS8bsQEQPlmwAEVYsAUvG7EFED5ZshIAARESObASL7EDAbAKK1gh2Bv0WbIHAxIREjmwABCxEwGwCitYIdgb9FkwMQERIxEjAyMTJiY1NDY3AxQWMzMRIyIGA9/y4+f8/2Rr6ca8ZU/v4FlqBDr7xgGN/nMBtSqcZZfBAv6gRFUBOFoAAAH/2/5LA/gGAAAhAI6yFSIjERI5ALAeL7AARViwBC8bsQQcPlmwAEVYsAovG7EKEj5ZsABFWLAYLxuxGBA+WbafHq8evx4DXbIvHgFdsg8eAV2yIRgeERI5sCEvsQAHsAorWCHYG/RZsgIYBBESObAKELEPAbAKK1gh2Bv0WbAEELEVAbAKK1gh2Bv0WbAAELAa0LAhELAc0DAxASEVNjMgExEUBiMiJzcWMzI1ETQmIyIHESMRIzUzNTMVIQJ3/vV3tgFaBbmmRjoPJzt7YV6SSPOenvMBCwSt6Yr+dfz+ssQRvw2/Au1wXYL8+wStq6ioAAABAFT/7AP5BE4AHQB9shYeHxESOQCwAEVYsA8vG7EPHD5ZsABFWLAILxuxCBA+WbEAAbAKK1gh2Bv0WbIZDwgREjl8sBkvGLQfGS8ZAnGxGwewCitYIdgb9FmyAwAbERI5tAQDFAMCXbAPELEWAbAKK1gh2Bv0WbITGRYREjmyHBMBXbILEwFdMDElMjY3Mw4CIyIAETU0ADMyFhcjJiYjIgYHIRUhEgI+WXgG5AN4ynTk/vgBCOTA9QTkB3Zbbn0KAVv+phmuaFBmsGQBJwECGfcBKeK2YHWUjaj+7AACAB4AAAaaBDoAFgAfAH2yCSAhERI5sAkQsBfQALAARViwAC8bsQAcPlmwAEVYsAgvG7EIED5ZsABFWLAPLxuxDxA+WbIBAAgREjmwAS+wABCxCgGwCitYIdgb9FmwDxCxEQGwCitYIdgb9FmwARCxFwGwCitYIdgb9FmwCBCxGAGwCitYIdgb9FkwMQERMxYWFRQGByERIQMCBgcjJzc2NjcTAREzMjY1NCYnA/r4w+Xpw/4Z/uYVE6ivTgIyUkcKFALz7VhoZFYEOv6HA7yfoMECA3b+h/7y7gHKBQuv4wHO/cX+wVhNSFEBAAIAhgAABrEEOgASABsAhbIBHB0REjmwARCwE9AAsABFWLACLxuxAhw+WbAARViwES8bsREcPlmwAEVYsAsvG7ELED5ZsABFWLAPLxuxDxA+WbIBEQsREjmwAS+yBBELERI5sAQvsAEQsQ0BsAorWCHYG/RZsAQQsRMBsAorWCHYG/RZsAsQsRQBsAorWCHYG/RZMDEBIREzETMWFhUUBgchESERIxEzAREzMjY1NCYjAXkBpfP4w+Xpw/4Z/lvz8wKY7VpmZFsCnwGb/ocDvJ+gwQIB3f4jBDr9xf7BWktGVAAB/+4AAAP4BgAAGAB7sgwZGhESOQCwFS+wAEVYsAQvG7EEHD5ZsABFWLAHLxuxBxA+WbAARViwDy8bsQ8QPlmyvxUBXbIvFQFdsg8VAV2yGA8VERI5sBgvsQAHsAorWCHYG/RZsgIEBxESObAEELEMAbAKK1gh2Bv0WbAAELAR0LAYELAT0DAxASEVNjMgExEjETQmIyIHESMRIzUzNTMVIQKL/uF3tgFaBfNhXpJI84uL8wEfBLXxiv51/T0CunBdgvz7BLWqoaEAAQCG/poEEgQ6AAsARgCwCC+wAEVYsAAvG7EAHD5ZsABFWLADLxuxAxw+WbAARViwBS8bsQUQPlmwAEVYsAkvG7EJED5ZsQEBsAorWCHYG/RZMDEBESERMxEhESMRIREBeQGm8/618/6yBDr8iAN4+8b+mgFmBDoAAQCI/+sGwQWwAB4AYbIGHyAREjkAsABFWLAALxuxACA+WbAARViwDC8bsQwgPlmwAEVYsBUvG7EVID5ZsABFWLAELxuxBBA+WbAARViwCC8bsQgQPlmyBgAEERI5sREBsAorWCHYG/RZsBrQMDEBERQGIyInBiMiJjURMxEUFjMyNjURIREUFjMyNjURBsH50uVtcenP8/1nXmlyAQFtY2FuBbD7/9bupaXv1QQB+/x1goF3BAP7/HSDf3kEAwAAAQBw/+sF7QQ6AB4AYbIGHyAREjkAsABFWLAALxuxABw+WbAARViwDC8bsQwcPlmwAEVYsBUvG7EVHD5ZsABFWLAELxuxBBA+WbAARViwCC8bsQgQPlmyBhUEERI5sREBsAorWCHYG/RZsBrQMDEBEQYGIyInBiMiJjURMxEUFjMyNjURMxEUFjMyNjURBe0B2r3HYGbLuNXzVEZTZvRcT0pbBDr9TsHcjo7dwwKv/VFybGxyAq/9UXJsbHICrwAAAv/gAAAEIQYYABIAGwB0shUcHRESObAVELAD0ACwAEVYsA8vG7EPIj5ZsABFWLAJLxuxCRA+WbISDwkREjmwEi+xAAewCitYIdgb9FmyAg8JERI5sAIvsAAQsAvQsBIQsA3QsAIQsRMBsAorWCHYG/RZsAkQsRQBsAorWCHYG/RZMDEBIREzFhYVFAYHIREjNTMRMxEhAREzMjY1NCYnAqP+3vfE5eXA/hKurvMBIv7e7VtlY1cEOv7JA86urdMEBDqrATP+zf1b/oJlWVVpAgAAAQCY/+0GzQXFACUAkbIOJicREjkAsABFWLAkLxuxJCA+WbAARViwBS8bsQUgPlmwAEVYsBwvG7EcED5ZsABFWLAiLxuxIhA+WbIAIiQREjmwAC+yHwABcbIIJBwREjmwBRCxDAGwCitYIdgb9FmwABCwD9CwABCxIQGwCitYIdgb9FmwEtCwHBCxFQGwCitYIdgb9FmyGCQcERI5MDEBMzYSJDMyABcjJiYjIgYHIRUhFhYzMjY3MwYAIyIkAicjESMRMwGUtQuWAQmr8QEmGPwSk46hqwsB6f4WAqiilZYU/Bb+0/is/viTA7T8/ANPvgEdm/76752L3czD4fKGnOn++6EBNMr9dAWwAAEAhv/sBboETgAjAJWyDSQlERI5ALAARViwBC8bsQQcPlmwAEVYsCMvG7EjHD5ZsABFWLAbLxuxGxA+WbAARViwIC8bsSAQPlmyDgQbERI5fLAOLxi0QA5QDgJdsADQsAQQsQsBsAorWCHYG/RZsggOCxESObAOELEPB7AKK1gh2Bv0WbAbELETAbAKK1gh2Bv0WbIWEw8REjmwDxCwHtAwMQEzNiQzMhYXIyYmIyIDIRUhFhYzMjY3Mw4CIyIkJyMRIxEzAXmdFAEE0sH1BOQHdlvbGgF8/oUKfW5ZeAbkA3jKdNP+/RSe8/MCcd7/4rZgdf7mq4qOaFBmsGT+3P46BDoAAgAcAAAFFwWwAAsADgBXALAARViwCC8bsQggPlmwAEVYsAIvG7ECED5ZsABFWLAGLxuxBhA+WbAARViwCi8bsQoQPlmyDQgCERI5sA0vsQABsAorWCHYG/RZsATQsg4IAhESOTAxASMRIxEjAyEBMwEhASEDA4N+4XOP/voCBvUCAP76/eABU6gBqv5WAar+VgWw+lACaAH4AAIACgAABEUEOgALABAAVwCwAEVYsAgvG7EIHD5ZsABFWLACLxuxAhA+WbAARViwBi8bsQYQPlmwAEVYsAovG7EKED5Zsg0CCBESObANL7EBAbAKK1gh2Bv0WbAE0LIPCAIREjkwMQEjESMRIwMjATMBIwEzAycHAuRdw1to9wGp5wGr9/5c+GQZGQEX/ukBF/7pBDr7xgHEAQZkZAAAAgCsAAAHMAWwABMAFgB9ALAARViwAi8bsQIgPlmwAEVYsBIvG7ESID5ZsABFWLAELxuxBBA+WbAARViwCC8bsQgQPlmwAEVYsAwvG7EMED5ZsABFWLAQLxuxEBA+WbIVAgQREjmwFS+wANCwFRCxBgGwCitYIdgb9FmwCtCwBhCwDtCyFgIEERI5MDEBIQEzASEDIxEjESMDIRMhESMRMwEhAwGoAWgBK/UCAP76jn7ico/++pj+2/z8AmIBU6kCZwNJ+lABqv5WAar+VgGr/lUFsPy4AfkAAgCdAAAGGAQ6ABMAGACAALAARViwAi8bsQIcPlmwAEVYsBIvG7ESHD5ZsABFWLAELxuxBBA+WbAARViwCC8bsQgQPlmwAEVYsAwvG7EMED5ZsABFWLAQLxuxEBA+WbIAEBIREjmwAC+wAdCxDgGwCitYIdgb9FmwC9CwB9CwARCwFNCwFdCyFxIEERI5MDEBMxMzASMDIxEjESMDIxMjESMRMwEzAycHAZD++OcBq/dqXcNbaPdtuvPzAe34ZBkZAcQCdvvGARf+6QEX/ukBF/7pBDr9igEGZGQAAAIAgAAABm4FsAAaAB0AfLIbHh8REjmwGxCwDdAAsABFWLAZLxuxGSA+WbAARViwBC8bsQQQPlmwAEVYsAwvG7EMED5ZsABFWLATLxuxExA+WbIAGQQREjmwAC+xCQGwCitYIdgb9FmwDtCwD9CwABCwGNCyGxkEERI5sBkQsRwBsAorWCHYG/RZMDEBFhYXESMRJiYjIwcRIxEjIgYHESMRNjYhASEBEyEEev7xBfwCdo9oBvx+j3UD/AP6AQ/+hQTk/Y7p/i8DKATZ2P6NAWyBbwv9rwJcbn7+kAFs4dsCiP2KAakAAgCCAAAFZAQ6ABoAHQB8shseHxESObAbELAU0ACwAEVYsAUvG7EFHD5ZsABFWLAALxuxABA+WbAARViwCy8bsQsQPlmwAEVYsBMvG7ETED5ZsgQFABESObAEL7AH0LAEELEQB7AKK1gh2Bv0WbAV0LAW0LIbBQAREjmwBRCxHAGwCitYIdgb9FkwMTM1NjY3ASEBFhYXFSM1JiYnIwcRIxEjIgYHFQETIYICxcz+6wP0/urGvgLzAV5yLwHyLXlgAwGFlf7Wss7SDQHb/iQR08ezsX9yAgP+XwGkbny6AmkBIgAAAgCjAAAIswWwACAAIwCZshwkJRESObAcELAj0ACwAEVYsAcvG7EHID5ZsABFWLALLxuxCyA+WbAARViwAC8bsQAQPlmwAEVYsAUvG7EFED5ZsABFWLARLxuxERA+WbAARViwGS8bsRkQPlmyCQcAERI5sAkvsQMBsAorWCHYG/RZsAkQsA3QsAMQsBzQsBfQsiEHABESObALELEiAbAKK1gh2Bv0WTAxIRE0NyERIxEzESEBIQEWFhcRIxEmJiMjBxEjESMiBgcRARMhAsU7/p/8/AMw/ocE5f6E/vEF/AJ2j2gF/H+RcwMCCOn+LgFgoWX9mgWw/XsChf14BNnY/o0BbIFvCf2tAlxxfP6RAzkBqgAAAgCPAAAHdgQ6ACAAIwCZsh0kJRESObAdELAj0ACwAEVYsAcvG7EHHD5ZsABFWLALLxuxCxw+WbAARViwAC8bsQAQPlmwAEVYsAUvG7EFED5ZsABFWLARLxuxERA+WbAARViwGS8bsRkQPlmyCQsAERI5sAkvsQMHsAorWCHYG/RZsAkQsA3QsAMQsBzQsBfQsiELABESObALELEiAbAKK1gh2Bv0WTAxITU2NyERIxEzESEBIQEWFhcVIzUmJicjBxEjESMiBgcVARMhApUBNf638/MCpf7sA/T+6sW+AvIBXnMuAfIteWADAYWV/tawlGT+WAQ6/icB2f4kEdTGs7F/cgID/l8BpG58ugJpASIAAAIAKP5AA6oHiAAnADAAqrICMTIREjmwAhCwKNAAsCwvsABFWLAFLxuxBSA+WbAARViwFy8bsRcSPlmwAEVYsBEvG7ERED5ZsAUQsQMBsAorWCHYG/RZsiYFERESOXywJi8YshAmAV2yQCYBXbRgJnAmAl2xIwGwCitYIdgb9FmyDCMmERI5sBEQsR0BsAorWCHYG/RZsg8sAV2wLBCwKdCwKS+0DykfKQJdsigsKRESObAw0LAwLzAxATQmIyE1ITIEFRQGBwQVFAQjIwYVFBcHJiYnNDY3MzY2NTQhIzUzIAM3MxUBIwE1MwKWhXr+5QEV7QELfW4BDP736DV6mFKEogKxpD9yif7PiYkBEJSTz/7ql/7rzgQhXmrHz7VwoyxX/sXoA2NrQZkot3+GiwIBfWXzxwOfmwr+6QEYCQAAAgAz/kgDiAYcACcAMACYsgIxMhESObACELAo0ACwLC+wAEVYsAUvG7EFHD5ZsABFWLAXLxuxFxI+WbAARViwEi8bsRIQPlmwBRCxBAGwCitYIdgb9FmyJRIFERI5fLAlLxi0QCVQJQJdsSQHsAorWCHYG/RZsgwkJRESObASELEdAbAKK1gh2Bv0WbAsELAp0LApL7QPKR8pAl2yKCksERI5sDDQMDEBNCYjITUhMhYVFAYHFhUUBiMjBhUUFwcmJic0NjczMjY1NCEjNTMyAzczFQEjATUzAnRzaf7kARfc+GFX2fbQNn6QUYKWAqmhNWx3/vmRleKgktD+6Zb+680C/jxHuaWNT3ckQqyWrwRia0GRMLZwfYcBUD+UqQMSmwv+6gEXCgADAF//7AUXBcQAEAAXAB4AabIEHyAREjmwBBCwEdCwBBCwGNAAsABFWLAMLxuxDCA+WbAARViwBC8bsQQQPlmwDBCxEQGwCitYIdgb9FmyFAQMERI5fLAULxiwBBCxGAGwCitYIdgb9FmwFBCxHAewCitYIdgb9FkwMQEUAgQjIiQCJzU0EiQgBBIXASIGByEmJgMyNjchFhYFF5T+7bOw/u6ZA5YBFAFkAROWAf2koLYIArwItKCfswr9RAq4ArLW/r2tqgE8zV3VAUSvq/6/1QHv8Nnb7vvK5d7Z6gADAE//7AQ9BE4ADwAWAB0AarIEHh8REjmwBBCwENCwBBCwF9AAsABFWLAELxuxBBw+WbAARViwDC8bsQwQPlmxEAGwCitYIdgb9FmyGwQMERI5fLAbLxi0QBtQGwJdsRMHsAorWCHYG/RZsAQQsRcBsAorWCHYG/RZMDETNDY2MzIAFxcUBgYjIgARATI2NyEWFhMiBgchJiZPfeSU2gETCwF755Xj/uwB92uFEP3/EIRraoUQAgAQhQInof2J/ufqOaD8igEuAQH+k5KJiJMC3ZWCgpUAAQAQAAAE8wXCAA8AR7ICEBEREjkAsABFWLAGLxuxBiA+WbAARViwDy8bsQ8gPlmwAEVYsAwvG7EMED5ZsgEMDxESObAGELEIAbAKK1gh2Bv0WTAxARc3EzY2MxcHIwYHASMBIQJhGxvkNZx6LQIYVCf+mPT+DgENAYtybwL3rJcB1wJ8+5QFsAAAAQAgAAAEGAROABEAR7ICEhMREjkAsABFWLAFLxuxBRw+WbAARViwES8bsREcPlmwAEVYsA4vG7EOED5ZsgEFDhESObAFELEKAbAKK1gh2Bv0WTAxARc3ExIzMhcHJiMiBgcBIwEzAeMUFHpaz0MnFwwgIjsN/vbT/pL7AW5hYQG+ASIWwAY2KvziBDoAAAIAX/92BRcGLgATACcAV7IFKCkREjmwBRCwIdAAsABFWLANLxuxDSA+WbAARViwAy8bsQMQPlmwBtCwDRCwENCwDRCxGgGwCitYIdgb9FmwF9CwAxCxJAGwCitYIdgb9FmwIdAwMQEQAAcVIzUmAAM1EAA3NTMVFgARJzQmJxUjNQYGFRUUFhc1MxU2NjUFF/7z6cbo/u8DARLpxuoBDf2CeMZ5hYR7xnmAArL+2v6LI35+IwFzAR1VASQBeiNxciP+hv7ZBs71I2BhI/XPTMf9JWBfI/bPAAIAT/+IBD0EtAATACUAWrIDJicREjmwAxCwFNAAsABFWLADLxuxAxw+WbAARViwEC8bsRAQPlmwAxCwBtCwEBCwDdCwEBCxIwGwCitYIdgb9FmwFNCwAxCxHQGwCitYIdgb9FmwGtAwMRM0Ejc1MxUWEhUVFAIHFSM1JgI1ATY2NTQmJxUjNQYGFRQWFzUzT929uL/d37+4u90CUFJaWlC4T1hWT7gCJ9oBJh9ubR/+2N0R2/7ZHWtsHwEm3f6nHrWXgrIfYGAhspWDriFoAAADAIj/6wa1Bz8AKgA9AEYAvrIwR0gREjmwMBCwCdCwMBCwRdAAsABFWLAALxuxACA+WbAARViwEi8bsRIgPlmwAEVYsAcvG7EHED5ZsABFWLALLxuxCxA+WbIJAAcREjmwEhCxEwGwCitYIdgb9FmwCxCxGgGwCitYIdgb9FmyHgsSERI5sCPQsBMQsCrQsBIQsDbQsDYvsCzQsCwvsSsIsAorWCHYG/RZsCwQsDLQsDIvsTkIsAorWCHYG/RZsCwQsELQsEIvsEbQsEYvMDEBMhYXERQGIyInBiMiJicRNDYzFSIGFREUFjMyNjURMxEWFjMyNjURNCYjExUjIi4CIyIVFSM1NDMyHgIBNjc1MxUUBgcE9M7yAfHQ43Jy487wBPPPX2ZmX2ly9QFxaF9mZl9qIVOKvzAUaIbrJUbJb/4pQQOpYDsFsPrd/erd+56e9tUCIN39zI6A/e2AjoF3AYL+eXOAjoACE4COAeOGI0sKaBAi3A9PGv6HUjxoZzF4HwAAAwB0/+sF0QXjACoAPQBGALOyCUdIERI5sAkQsDrQsAkQsEbQALAARViwEi8bsRIcPlmwAEVYsAsvG7ELED5ZsBIQsADQsAAvsAsQsAfQsgkSCxESObASELETAbAKK1gh2Bv0WbALELEaAbAKK1gh2Bv0WbIeCxIREjmwI9CwExCwKtCwEhCwNtCwNi+wLdCwLS+xKwiwCitYIdgb9FmwLRCwMtCwMi+xOQiwCitYIdgb9FmwNhCwQdCwQS+wRtCwRi8wMQEyFhcVFAYjIicGIyImJxE0NjMVIgYVFRQWMzI2NzUzFRYWMzI2NTU0JiMTFSMiLgIjIhUVIzU0MzIeAgE2NzUzFRQGBwQ6utwB1LXFYWPCstME3LtJW1NDUF4B7AFeUUJUW0m9JFOKwSwVaIfrJUbFcP4wQQOpYDsER+XM+MznkZHgxQEDzefDdXz1fHVwasrKanB1fPV8dQHnhiNMCWgQItwPThv+hVI8aGcxeB8AAgCI/+sGwQcRAB4AJgB/sgYnKBESObAGELAj0ACwAEVYsA0vG7ENID5ZsABFWLAILxuxCBA+WbAE0LIGCA0REjmwCBCxEQGwCitYIdgb9FmwDRCwFdCwFS+wERCwGtCwFRCwHtCwHi+wDRCwJdCwJS+wJtCwJi+xIAiwCitYIdgb9FmwJhCwI9CwIy8wMQERFAYjIicGIyImNREzERQWMzI2NREhERQWMzI2NRElNSEXIRUjNQbB+dLlbXHpz/P9Z15pcgEBbWNhbvw5A1UB/qa1BbD7/9bupaXv1QQB+/x1goF3BAP7/HSDf3kEA+d6en9/AAIAcP/rBe0FsQAeACYAi7IGJygREjmwBhCwJdAAsABFWLANLxuxDRw+WbAARViwFS8bsRUcPlmwAEVYsB4vG7EeHD5ZsABFWLAELxuxBBA+WbAARViwCC8bsQgQPlmyBggVERI5sREBsAorWCHYG/RZsBrQsA0QsCXQsCUvsB/QsB8vsSAIsAorWCHYG/RZsB8QsCLQsCPQMDEBEQYGIyInBiMiJjURMxEUFjMyNjURMxEUFjMyNjURJTUhFyEVIzUF7QHavcdgZsu41fNURlNm9FxPSlv8nQM4BP6ytQQ6/U7B3I6O3cMCr/1RcmxscgKv/VFybGxyAq/8e3t/fwABAGb+jAS2BcUAGABVshcZGhESOQCwAEVYsAovG7EKID5ZsABFWLAALxuxABg+WbAARViwAi8bsQIQPlmwChCwDtCwChCxEAGwCitYIdgb9FmwAhCxFwGwCitYIdgb9FkwMQEjESYANRE0EiQzIAAVIxAhIgYVERQWFzMDNPvT/wCNAQGjAQABH/z+3YypqYqf/owBZiABR/kBEa8BGJv+9+kBJt+8/u223wEAAQBc/okD8wROABoAVbIZGxwREjkAsABFWLAKLxuxChw+WbAARViwAC8bsQAYPlmwAEVYsAIvG7ECED5ZsAoQsA/QsAoQsRIBsAorWCHYG/RZsAIQsRkBsAorWCHYG/RZMDEBIxEmAjU1NDY2MzIWFhUjNCYjIgYVFRQWFzMC1fOz03nbknzGb+V0WHGCfnCY/okBaiABI9wcm/yJZ7t2W3q9qBuhuwIAAQBtAAAEkwU+ABMAEwCwDi+wAEVYsAQvG7EEED5ZMDEBBQclAyMTJTcFEyU3BRMzAwUHJQJbASFI/t21r+H+30cBJcr+3kkBI7ms5AElTP7gAcGsgKr+wQGOq4CrAWirgqsBRv5rq3+qAAH8ZgSi/zkF/QAHABIAsAAvsQMGsAorWCHYG/RZMDEBFSc3IScXFf0XsQECIgGxBSB+Ae5sAdwAAfxzBRf/bQYVAA8AMACwCy+wB9CwBy+xAAiwCitYIdgb9FmwCxCwBNCwBC+wCxCxDAiwCitYIdgb9FkwMQEyFRUjNTQjIgQHIzUzNiT+f+6Iajb+4ospJ3kBGAYV3CIQaHcBhgF3AAAB/XsFFv5yBmAABQAMALABL7AF0LAFLzAxATUzBxcH/Xu9ATtSBdyElnBEAAH9pQUW/pwGYAAFAAwAsAMvsADQsAAvMDEBJzcnMxX991I7Ab0FFkRwloQACPok/sQBvwWvAAwAGgAnADUAQgBPAFwAagB/ALBFL7BTL7BgL7A4L7AARViwAi8bsQIgPlmxCQmwCitYIdgb9FmwRRCwENCwRRCxTAmwCitYIdgb9FmwF9CwUxCwHtCwUxCxWgmwCitYIdgb9FmwJdCwYBCwK9CwYBCxZwmwCitYIdgb9FmwMtCwOBCxPwmwCitYIdgb9FkwMQE0NjIWFSM0JiMiBhUBNDYzMhYVIzQmIyIGFRM0NjMyFhUjNCYiBhUBNDYzMhYVIzQmIyIGFQE0NjIWFSM0JiMiBhUBNDYyFhUjNCYjIgYVATQ2MzIWFSM0JiIGFRM0NjMyFhUjNCYjIgYV/RFzvnRwMzAuMwHedF1fdXE1LiwzSHVdX3RwNVwz/st0XV90cDUuLTP9T3O+dHAzMC4z/U10vnRwMzAuM/7edV1fdHA1XDM1dV1fdXE1Li0zBPNUaGhULjc1MP7rVGhnVTE0NTD+CVVnaFQxNDcu/flUaGhUMTQ3Lv7kVGhoVC43Ny4FGlRoaFQuNzUw/glVZ2hUMTQ3Lv35VWdnVTE0NTAAAAj6Tf5jAYwFxgAEAAkADgATABgAHQAiACcALwCwIS+wFi+wEi+wCy+wGy+wJi+wAEVYsAcvG7EHID5ZsABFWLACLxuxAhI+WTAxBRcDIxMDJxMzAwE3BRUlBQclNQUBNyUXBQEHBSclAycDNxMBFxMHA/5QC3pgRjoMemBGAh0NAU3+pvt1Df6zAVoDnAIBQET+2/zzAv7ARQEmKxGUQcYDYBGUQsQ8Dv6tAWEEog4BUv6g/hEMfGJHOwx8YkcBrhCZRMj8jhGZRcgC5AIBRkX+1fzjAv67RwErAP//AJT+fgXdByQAJgDcAAAAJwChARwBPgEHABAEgP/GABMAsABFWLAILxuxCCA+WbAN3DAxAP//AIb+fgTkBdkAJgDwAAAAJwChAJf/8wEHABADh//GABMAsABFWLAILxuxCBw+WbAN3DAxAAAC/+AAAAQhBmIAEgAbAHeyFRwdERI5sBUQsAPQALAARViwDS8bsQ0gPlmwAEVYsBEvG7ERID5ZsABFWLAJLxuxCRA+WbARELEAB7AKK1gh2Bv0WbICDQkREjmwAi+wABCwC9CwDNCwAhCxEwGwCitYIdgb9FmwCRCxFAGwCitYIdgb9FkwMQEhETMWFhUUBgchESM1MzUzFSEBETMyNjU0JicCo/7e98Tl5cD+Eq6u8wEi/t7tW2VjVwUF/f4Dzq6t0wQFBauysvyQ/oJlWVVpAgACAJQAAATZBbAADgAbAE+yBBwdERI5sAQQsBfQALAARViwAy8bsQMgPlmwAEVYsAEvG7EBED5ZshYDARESObAWL7EAAbAKK1gh2Bv0WbADELEUAbAKK1gh2Bv0WTAxAREjESEyBBUUBxcHJwYjEzY1NCYnIREhMjcnNwGR/QIt9AEfdXptiHmq+RyQfv7JATBPOnNuAh394wWw/tHBd4dkljcBQzVKdo0C/gQWgGQAAAIAfP5gBDAETgATACIAcLIXIyQREjmwFxCwENAAsABFWLAQLxuxEBw+WbAARViwDS8bsQ0cPlmwAEVYsAovG7EKEj5ZsABFWLAHLxuxBxA+WbIJEAcREjmyDhAHERI5sBAQsRcBsAorWCHYG/RZsAcQsRwBsAorWCHYG/RZMDEBFAcXBycGIyInESMRMxc2MzISESc0JiMiBxEWMzI3JzcXNgQwbmpvaFlwsmvz4ApruMbh8oF4lUFClkYyam5ZIgIS9Jd6Y3g2df3/Bdpugv7Z/voGor57/iB+IXtkZ1gAAQCPAAAENAcQAAkANrIDCgsREjkAsAgvsABFWLAGLxuxBiA+WbAARViwBC8bsQQQPlmwBhCxAgGwCitYIdgb9FkwMQEjFSERIxEhETMENAj9YP0CsvME7Qn7HAWwAWAAAQB+AAADWwVzAAcALACwAEVYsAQvG7EEHD5ZsABFWLACLxuxAhA+WbAEELEAAbAKK1gh2Bv0WTAxASERIxEhETMDW/4W8wHr8gN2/IoEOgE5AAEAm/7GBJ0FsAAUAF6yDxUWERI5ALAJL7AARViwEy8bsRMgPlmwAEVYsBEvG7ERED5ZsBMQsQABsAorWCHYG/RZsgMTCRESObADL7AJELEKB7AKK1gh2Bv0WbADELEPAbAKK1gh2Bv0WTAxASERMyAAERAAIycyNjUCJSMRIxEhBDf9YKgBIgE8/vbzAYOIAv6rvPwDnATk/l/+zf7s/vT+1rqzwgF7Cf2HBbAAAAEAfv7iA9sEOgAVAEyyCxYXERI5ALAKL7AARViwFC8bsRQcPlmwAEVYsBIvG7ESED5ZsBQQsQABsAorWCHYG/RZsgMUChESObADL7EQAbAKK1gh2Bv0WTAxASEVMyAAFRQGBgcnNjU0JiMjESMRIQNG/itJAQEBIF6rc1Xem45O8wLIA3bl/vrdYMKNHa5K1IGX/joEOgD//wAW/poIBQWwACYA2gAAAAcCUQa2AAD//wAe/poGtAQ6ACYA7gAAAAcCUQVlAAD//wCb/poFfwWwACYCLAAAAAcCUQQwAAD//wCP/poEwgQ6ACYA8QAAAAcCUQNzAAAAAQCQAAAFNgWwABQAYgCwAEVYsAAvG7EAID5ZsABFWLAMLxuxDCA+WbAARViwAi8bsQIQPlmwAEVYsAovG7EKED5Zsg8KDBESObAPL7KfDwFdsQgBsAorWCHYG/RZsgEIDxESObAF0LAPELAS0DAxCQIhASMVIzUjESMRMxEzNTMVMwEFDf58Aa3+wf7TQaNZ/f1ZozcBGwWw/Vv89QJt6en9kwWw/Zr+/gJmAAEAjgAABK4EOgAUAF0AsABFWLANLxuxDRw+WbAARViwFC8bsRQcPlmwAEVYsAovG7EKED5ZsABFWLADLxuxAxA+WbIOCg0REjmwDi+xCQGwCitYIdgb9FmyAQkOERI5sAXQsA4QsBLQMDEJAiEDIxUjNSMRIxEzETM1MxUzEwSU/sQBVv7L2C+bV/LyV5snzwQ6/f79yAGssrL+VAQ6/lDHxwGwAAABADQAAAaiBbAADgBjALAARViwBi8bsQYgPlmwAEVYsAovG7EKID5ZsABFWLACLxuxAhA+WbAARViwDS8bsQ0QPlmyCAYCERI5sAgvsQEBsAorWCHYG/RZsAYQsQQBsAorWCHYG/RZsgwBCBESOTAxASMRIxEhNSERMwEhAQEhA7at/P4nAtWLAa0BNv4MAh/+0AJw/ZAE7MT9nAJk/Uf9CQABAD0AAAWoBDoADgBtALAARViwBi8bsQYcPlmwAEVYsAovG7EKHD5ZsABFWLACLxuxAhA+WbAARViwDS8bsQ0QPlmyCQoCERI5sAkvsi8JAXGyjAkBXbEAAbAKK1gh2Bv0WbAGELEEAbAKK1gh2Bv0WbIMAAkREjkwMQEjESMRITUhETMBIQEBIQNAe/L+agKIbAEqAS3+eAGo/sUBrP5UA3bE/lABsP35/c3//wCU/poF2wWwACYALAAAAAcCUQSMAAD//wCG/poE1QQ6ACYA9AAAAAcCUQOGAAAAAQCUAAAHgwWwAA0AiQCwAEVYsAIvG7ECID5ZsABFWLAMLxuxDCA+WbAARViwBi8bsQYQPlmwAEVYsAovG7EKED5ZsgECBhESObABL7KfAQFdsm8BAXGy3wEBcbIPAQFysp8BAXGyPwEBcbQvAT8BAnKyfAEBXbACELEEAbAKK1gh2Bv0WbABELEIAbAKK1gh2Bv0WTAxASERIRUhESMRIREjETMBkQKLA2f9lfz9df39A1ICXsP7EwKH/XkFsAAAAQB+AAAFZgQ6AA0AaACwAEVYsAIvG7ECHD5ZsABFWLAMLxuxDBw+WbAARViwBi8bsQYQPlmwAEVYsAovG7EKED5ZsgEMBhESOXywAS8YtEABUAECXbACELEEAbAKK1gh2Bv0WbABELEIAbAKK1gh2Bv0WTAxASERIRUhESMRIREjETMBcQGlAlD+o/P+W/PzAncBw8T8igG1/ksEOgABAJv+xAfvBbAAFgBrshAXGBESOQCwBy+wAEVYsBUvG7EVID5ZsABFWLATLxuxExA+WbAARViwEC8bsRAQPlmyARUHERI5sAEvsAcQsQgHsAorWCHYG/RZsAEQsQ0BsAorWCHYG/RZsBUQsREBsAorWCHYG/RZMDEBMyAAERAAIycyNjUCJSMRIxEhESMRIQUUfQEiATz+9vMBg4gC/quR/P1//AR5A0H+zf7s/vT+1rqzwgF7Cf2JBOT7HAWwAAABAH7+5ga6BDoAGABZshIZGhESOQCwCC+wAEVYsBcvG7EXHD5ZsABFWLAVLxuxFRA+WbAARViwEi8bsRIQPlmyARcIERI5sAEvsQ8BsAorWCHYG/RZsBcQsRMBsAorWCHYG/RZMDEBMyAAFRQGBgcnNjY1NCYjIxEjESERIxEhBAp9AQcBLF2rc1V1aaWaf/P+WvMDjAKU/vveYb+OHa0oj2eCl/42A3b8igQ6AAACAGf/6wXXBcUAJQAyAImyFjM0ERI5sBYQsCbQALAARViwDS8bsQ0gPlmwAEVYsB0vG7EdID5ZsABFWLAELxuxBBA+WbAA0LAAL7ICBB0REjmwAi+wDRCxDgGwCitYIdgb9FmwBBCxFQGwCitYIdgb9FmwABCxJQGwCitYIdgb9FmwAhCwKdCwHRCxLwGwCitYIdgb9FkwMQUiJwYjIiQCJzU0EjYzFSIGFRUUEjMyNyYRNTQSMzISERUQBxYzARQWFzYRNTQmIyIGFQXX37OUt7v+1KkDfeGMZn7bsjEp4u24wvO7XGr9jmVjomBYVF4VR0euATa/ya8BHqHU4b241/75B8sBRMvwATX+v/76xv7ayhQCGYTVSI8BCdWuq6+hAAIAYf/rBMkETgAiAC4AkLIELzAREjmwBBCwI9AAsABFWLALLxuxCxw+WbAARViwGi8bsRocPlmwAEVYsAQvG7EEED5ZsABFWLAALxuxABA+WbICBBoREjmwAi+wCxCxDAGwCitYIdgb9FmwBBCxEwGwCitYIdgb9FmwABCxIgOwCitYIdgb9FmwAhCwJdCwGhCxKwGwCitYIdgb9FkwMQUiJwYjIgARNTQSMxUGBhUVFBYzNyY1NTQ2MzIWFRUUBxYzARQXNjU1NCYjIgYVBMm6k3qQ5f7U26pAS5p9JY+2lJa9gU1Y/g54Yz0xMjsSNjkBQgEEQs8BDMoElHtJpswCleJ6u+r/zXfTlBEBj6psY6l7a4d4av//ACn+mgUiBbAAJgA8AAAABwJRA9MAAP//AB/+mgQnBDoAJgBcAAAABwJRAtgAAAABAC3+oQa3BbAADwBRALANL7AARViwCC8bsQggPlmwAEVYsAIvG7ECID5ZsABFWLAOLxuxDhA+WbACELEAAbAKK1gh2Bv0WbAF0LAOELEGAbAKK1gh2Bv0WbAK0DAxASE1IRUhESERMxEzAyMRIQGN/qADvv6fAoH8sBTn+9EE7MTE+94E5vsc/dUBXwAAAQAm/r8FOgQ6AA8ATQCwDS+wAEVYsAMvG7EDHD5ZsABFWLAPLxuxDxA+WbADELEEAbAKK1gh2Bv0WbAA0LAPELEGAbAKK1gh2Bv0WbADELAI0LAGELAK0DAxASM1IRUjESERMxEzAyMRIQEb9QLD2wGm85MU3fzSA3fDw/1LA3j8iP39AUEA//8Ajv6aBa0FsAAmAOEAAAAHAlEEXgAA//8AX/6aBKQEOwAmAPkAAAAHAlEDVQAAAAEAgAAABOEFsAAYAFCyBRkaERI5ALAARViwAC8bsQAgPlmwAEVYsAsvG7ELID5ZsABFWLAOLxuxDhA+WbIFDgAREjmwBS+wCNCwBRCxFAGwCitYIdgb9FmwEdAwMQERFhcWFxEzETY3ETMRIxEGBxUjNSYmJxEBfQJPNW6jbGT9/WBwo/b6AQWw/iyYOScFASv+3AoZAqf6UAI8GArr5Qbq3wHNAAABAHQAAAP1BDsAFgBSsgYXGBESOQCwAEVYsBUvG7EVHD5ZsABFWLAMLxuxDBw+WbAARViwAS8bsQEQPlmyDwEMERI5fLAPLxixBwGwCitYIdgb9FmwBNCwDxCwEtAwMSEjEQYHFSM1JiYnETMRFhcRMxE2NxEzA/XzRTGjtr4B8gGCozs78wFpDgWKixPQsQFQ/rCsHwEL/u8GDgIMAAEAhAAABOUFsAARAEeyBRITERI5ALAARViwAS8bsQEgPlmwAEVYsAAvG7EAED5ZsABFWLAJLxuxCRA+WbIFAQAREjmwBS+xDgGwCitYIdgb9FkwMTMRMxE2MyAEFxEjESYmIyIHEYT9oLIBBgEKAv0BfpaupAWw/cIp5+X+MQHPi3Yq/VoAAgAW/+kFvAXEABwAJABnshYlJhESObAWELAj0ACwAEVYsA4vG7EOID5ZsABFWLAALxuxABA+WbIeAA4REjmwHi+xEgGwCitYIdgb9FmwBNCwHhCwCtCwABCxFwGwCitYIdgb9FmwDhCxIgGwCitYIdgb9FkwMQUgABE1JiY1MxQXNBIkFyAAERUhFRQWMzI3FwYGASE1NCYjIgYD3P7S/qqbp7WNlAEIngEIASL8mMu9sawxQ9j+BQJsmpSOsBcBVAErPBjUqrYqrgEcoAH+nP65hDXK10bFKC4DbB+4wN0AAAL/y//sBIsETgAaACEAj7IgIiMREjmwIBCwFNAAsABFWLANLxuxDRw+WbAARViwAC8bsQAQPlmyHAANERI5sBwvtL8czxwCXbRfHG8cAnG0HxwvHAJxso8cAV207xz/HAJxsREHsAorWCHYG/RZsATQsBwQsArQsAAQsRUBsAorWCHYG/RZshcADRESObANELEgAbAKK1gh2Bv0WTAxBSIkJycmJjUzFBc2JDMyEhEVIRYWMzI3FwYGASE1JiYiBgLY1P7mFAOChqloHwEHu93x/T0LnXeoZ4RB2v5tAc8Icsp6FPvRMh3Bk5UwxfP+5v7+Yoach31hawKWEnp9jAABAJD+vwTtBbAAFgBoshUXGBESOQCwEC+wAEVYsAQvG7EEID5ZsABFWLAILxuxCCA+WbAARViwAi8bsQIQPlmyBwQCERI5fLAHLxi0AAcQBwJdsArQsBAQsREBsAorWCHYG/RZsAcQsRYBsAorWCHYG/RZMDEBIxEjETMRMwEhARYAFRAAIycgEQIlIQGVCP39cQGyATL+IukBAP7w9AEBCQL+rv74AnH9jwWw/aQCXP2KH/7X+f7z/tPCAW8BegYAAAEAjv7qBEMEOgAWAFqyDRcYERI5ALAHL7AARViwES8bsREcPlmwAEVYsBUvG7EVHD5ZsABFWLAPLxuxDxA+WbIUFQ8REjl8sBQvGLRAFFAUAl2xDgGwCitYIdgb9FmyABQOERI5MDEBFhYVFAYGByc2JzQmJyMRIxEzETMBIQLNr7xeqnNV4AKNi67y8lUBQQEtAmEp461guogcrUfKdoUJ/lQEOv5QAbD//wAt/n4F2wWwACYA3QAAAAcAEAR+/8b//wAh/n4E5QQ6ACYA8gAAAAcAEAOI/8YAAQCb/ksFEwWwABQAdrIKFRYREjkAsABFWLAALxuxACA+WbAARViwAy8bsQMgPlmwAEVYsBIvG7ESED5ZsABFWLAILxuxCBI+WbICABIREjl8sAIvGLRgAnACAl20MAJAAgJdsAgQsQ0BsAorWCHYG/RZsAIQsRABsAorWCHYG/RZMDEBESERMxEUBiMiJzcWMzI1ESERIxEBlwJ//b6pRTwOJD57/YH8BbD9gwJ9+hi3xhHHDLoCmP2XBbAAAAEAfv5LBAkEOgAUAG+yCxUWERI5ALAARViwAC8bsQAcPlmwAEVYsAMvG7EDHD5ZsABFWLASLxuxEhA+WbAARViwCC8bsQgSPlmyAgMSERI5fLACLxi0QAJQAgJdsAgQsQ0BsAorWCHYG/RZsAIQsRABsAorWCHYG/RZMDEBESERMxEGBiMiJzcWMzI1ESERIxEBcQGl8wG6pkU6Dyc7fP5b8wQ6/j0Bw/uFs8ERvw3AAef+SwQ6AP//AJT+fgXoBbAAJgAsAAAABwAQBIv/xv//AIb+fgTiBDoAJgD0AAAABwAQA4X/xv//AJT+fgcxBbAAJgAxAAAABwAQBdT/xv//AI/+fgZBBDoAJgDzAAAABwAQBOT/xgACAFH/6wUeBcQAFgAeAGGyCB8gERI5sAgQsBfQALAARViwAC8bsQAgPlmwAEVYsAgvG7EIED5Zsg0ACBESObANL7AAELEQAbAKK1gh2Bv0WbAIELEXAbAKK1gh2Bv0WbANELEaAbAKK1gh2Bv0WTAxASAAERUUAgQnIAARNSEmJiMiBwcnNzYBMjY3IRUUFgJxAUABbaD+46n+3P69A9AF38ynlzQxG6YBKZa+Ev0vugXE/oz+tmvB/sKxAQFgAUmJ4PA0E8YNSvr82r0fub8AAQBb/+sESwWwABsAbrILHB0REjkAsABFWLACLxuxAiA+WbAARViwCy8bsQsQPlmwAhCxAAGwCitYIdgb9FmyBAIAERI5shsLAhESOXywGy8YsAXQshALAhESObALELETAbAKK1gh2Bv0WbAbELEZB7AKK1gh2Bv0WTAxASE1IRcBFhYVFAQjIiYmNTMUFjMyNjU0JiMjNQL//ZIDkQH+hsja/uXqi+J+/IdoeZCZkYwE5Myj/k8Y6sLF6Ge/g1+Af2SUhawAAQBd/nUERgQ6ABsAX7ILHB0REjkAsAsvsABFWLACLxuxAhw+WbEAAbAKK1gh2Bv0WbIEAAIREjmyGwsCERI5sBsvsAXQshALAhESObALELETAbAKK1gh2Bv0WbAbELEZB7AKK1gh2Bv0WTAxASE1IRcBFhYVFAQjIiYmNTMUFjMyNjU0JiMjNQL0/ZsDjAH+iMvX/urrieR784lsepSak48DdsSb/kMZ6b/C6mi/gWCFgGmWg6sA//8ANP5LBIkFsAAmALFSAAAmAiakKQAHAlQBNQAA//8ALf5JA6IEOgAmAOxVAAAnAib/nf96AAcCVAEL//7//wAp/ksFUQWwACYAPAAAAAcCVAPDAAD//wAf/ksEVQQ6ACYAXAAAAAcCVALHAAAAAgBSAAAEgwWwAAsAFABSsgQVFhESObAEELAO0ACwAEVYsAEvG7EBID5ZsABFWLADLxuxAxA+WbIAAQMREjmwAC+wAxCxDAGwCitYIdgb9FmwABCxDQGwCitYIdgb9FkwMQERMxEhIiYmNTQkNwERISIGFRQWFwOG/f3ane6AARXrATT+13ySi3kDmwIV+lB01IjM/AP9LwIGiXV0kQMAAAIAaAAABrAFsAAYACEAYrIHIiMREjmwBxCwGdAAsABFWLAILxuxCCA+WbAARViwAC8bsQAQPlmyBwgAERI5sAcvsAAQsQoBsAorWCHYG/RZshEIABESObAZ0LAHELEaAbAKK1gh2Bv0WbAZELAh0DAxISIkNTQkNyERMxEzNjY3NiYnMxYWBwYGByURISIGFRQWFwJy7P7iARXrATT8S15sBQIhHfUfJgIE88z+sf7WfZCOev3TzvoDAhX7GgKKfUrZTF7MRdT8A8oCBop0dZIBAAIAXv/nBn8GGAAfACsAhrIZLC0REjmwGRCwKtAAsABFWLAGLxuxBiI+WbAARViwAy8bsQMcPlmwAEVYsBgvG7EYED5ZsABFWLAcLxuxHBA+WbIFAxgREjmwGBCxCwGwCitYIdgb9FmyEAMYERI5shoDGBESObADELEiAbAKK1gh2Bv0WbAcELEoAbAKK1gh2Bv0WTAxExASMzIXETMRBhYzNjY3NiczFxYHDgIjBCcGIyICJwEmIyIGFRQWMzI3J17kw6Nl8wJOQ3SCBARA7BcvAwJ94oz+/1Vry7ngCwKuR4Nzf3p2jUUGAg4BCgE2eAJC+09PaQK3qb7VWbeDqPmFBLezAQXeAVFowc2eqnJEAAABADz/5wXjBbAAKQBmsiMqKxESOQCwAEVYsAkvG7EJID5ZsABFWLAiLxuxIhA+WbIBKgkREjmwAS+xAAGwCitYIdgb9FmwCRCxBwGwCitYIdgb9FmyDwABERI5sCIQsRUBsAorWCHYG/RZshoiCRESOTAxEzUzNjY1NCEhNSEWBBUUBxYTFQYWMzY2NzYnMxYWBw4CIwYmJzU0JiPmp5OE/vP+pQFk+gEG//YFATwzZXIEBED1GisCAnraiqeyCHxnAmLNAW110c0B08zmZD/+/k05SQK2o77VYspnqfiFBKeqPm5+AAEAL//iBP4EOgAkAGOyDyUmERI5ALAARViwHS8bsR0cPlmwAEVYsA4vG7EOED5ZsQIBsAorWCHYG/RZsgcOHRESObIWJR0REjmwFi+xFAewCitYIdgb9FmwHRCxGwGwCitYIdgb9FmyIhQWERI5MDElBjM2Njc2JzMWFgcGBiMGJic1NCMjJzM2NTQjIychFhYQBxYXAwECTlpgAwRB7C0YAQTpvJ6gCKLmAsK5y/8GARTL5LC5ButYAo9/lqmGgDnM8gNxg0h/vQSDlsMCpv7KSjCsAAABAEj+ugQ3BbAAIgBisgsjJBESOQCwFy+wAEVYsAkvG7EJID5ZsABFWLAbLxuxGxA+WbIBCRsREjmwAS+xAAGwCitYIdgb9FmwCRCxBwGwCitYIdgb9FmyDwABERI5sBsQsRIBsAorWCHYG/RZMDETJzM2NjU0ISEnIRYEFRQHFhMVMxUUBgcnNjY3IyYnNTQmI5cBzpGB/uv+6gMBLu8BA+TjA81kWoMkOAijPAN+dAJcwwFzb+vDA9zJ32ZH/vaGrGPYS005d0kxsYRxhQAAAQB0/qkEGgQ6ACIAYrIGIyQREjkAsBgvsABFWLAJLxuxCRw+WbAARViwHC8bsRwQPlmyAQkcERI5sAEvsQAHsAorWCHYG/RZsAkQsQcBsAorWCHYG/RZshAAARESObAcELETAbAKK1gh2Bv0WTAxEyczMjU0JiMhJyEyFxYVFAcWFxUzFRQGByc2NjcjJic1NCOzAeHSa2P+4QQBION4aq2xArtoVYMmOAamKwHDAZuzjkpTwWRZkp5PPMMkrGXaR009fk8eg1SmAAEAQv/rB38FsAAiAGWyACMkERI5ALAARViwDS8bsQ0gPlmwAEVYsB8vG7EfED5ZsABFWLAGLxuxBhA+WbANELEAAbAKK1gh2Bv0WbAGELEIAbAKK1gh2Bv0WbAfELESAbAKK1gh2Bv0WbIXHw0REjkwMQEhAwICBgcjNTc2NhMTIREUFjMyNjc2JzMWFgcOAiMiJjUEB/5hGA5huZxKKHpoDxwDjkw/bn8EBEH2HCkCAn/gjMPGBOP94P72/tOKAsoDCd8BHALf+7xSZLSnu9hmx2an+4TBvQAAAQBA/+sGWgQ6ACEAZbIgIiMREjkAsABFWLAMLxuxDBw+WbAARViwHi8bsR4QPlmwAEVYsAUvG7EFED5ZsAwQsQABsAorWCHYG/RZsAUQsQcBsAorWCHYG/RZsB4QsREBsAorWCHYG/RZshYeDBESOTAxASEDAgYHIyc3NjY3EyERFhYzMjY3NiczFxYHDgIjIiYnAxf+9xMRqK1TAjJQSQoUAuEBUUVYZwQEQOwWMAMCcMd9wscBA3T+mv7p9APKBQut5QHO/StSZKCZtchQsXyb5ny+uQAAAQCU/+cHhgWwAB0AZ7IUHh8REjkAsABFWLAALxuxACA+WbAARViwGS8bsRkgPlmwAEVYsBcvG7EXED5ZsABFWLARLxuxERA+WbEEAbAKK1gh2Bv0WbIJABcREjmyHAAXERI5sBwvsRUBsAorWCHYG/RZMDEBERQWMzY2NzYnMxcWBw4CIwYmJzUhESMRMxEhEQUKTT5wfgQEQfYXLwMCfOKOu8MJ/YL8/AJ+BbD7vFZgArOmu9hZt4Oo94cEwMP//ZcFsP2DAn0AAAEAd//jBlwEOgAcAHqyGx0eERI5ALAARViwBC8bsQQcPlmwAEVYsAgvG7EIHD5ZsABFWLACLxuxAhA+WbAARViwGi8bsRoQPlmyBwgCERI5fLAHLxi00AfgBwJdtEAHUAcCXbEAAbAKK1gh2Bv0WbAaELENAbAKK1gh2Bv0WbISCAIREjkwMQEhESMRMxEhETMRBhYzNjY3NiczFhYHDgIjBAMDGv5Q8/MBsPMCUkZeZAMEQOsaKwICcMd+/ooTAbr+RgQ6/kMBvf0tUmYCppGvzl2/YZvmfAgBhAABAF3/6wS7BcUAIQBJsgAiIxESOQCwAEVYsAkvG7EJID5ZsABFWLAALxuxABA+WbAJELEOAbAKK1gh2Bv0WbAAELEVAbAKK1gh2Bv0WbIaAAkREjkwMQUiJAInETQSJDMyFwcmIyIGFREUFjM2Njc2JzMXFgcOAgK7rP7rmwKaARet34g/hqKdxcSefYMDAzX1JxMBAoHqFZwBGK0BD68BHZ5ZuETnvP8AtukChXSVzLFYWIvNbgAAAQBV/+sD5wROAB4ARrITHyAREjkAsABFWLATLxuxExw+WbAARViwCy8bsQsQPlmxAAGwCitYIdgb9FmyBQsTERI5sBMQsRgBsAorWCHYG/RZMDElNjY3NCczFgcGBiMiADU1NDY2MzIXByYjIgYVFRQWAlpRRQIT6x0CBNK15/7ifOKSu2AuY4pyi5SvAkNHd2eMUqCwATH4Hpf6i0K9Or2kIJq/AAEAIf/nBVoFsAAZAE+yBRobERI5ALAARViwAi8bsQIgPlmwAEVYsBYvG7EWED5ZsAIQsQABsAorWCHYG/RZsATQsAXQsBYQsQkBsAorWCHYG/RZsg4WAhESOTAxASE1IRUhERQWMzY2NzYnMxYWBw4CIwYmJwHj/j4EgP4+TT5wfgQEQfUbKwMCfeKMu8MJBOPNzfyHVGACtqO72GLKZ6j5hQTAwwABAET/4wTLBDoAFwBPsgUYGRESOQCwAEVYsAIvG7ECHD5ZsABFWLAVLxuxFRA+WbACELEAAbAKK1gh2Bv0WbAE0LAF0LAVELEJAbAKK1gh2Bv0WbIOFQIREjkwMQEhNSEVIREUFjM2Njc2JzMWFgcGBiMEAwGJ/rsDi/6tUkVeYwMEQOssGQEE8cL+iRMDd8PD/fBUZAKEdJOefH43zPIIAYQAAAEAgf/rBP8FxQAoAHayJikqERI5ALAARViwFi8bsRYgPlmwAEVYsAsvG7ELED5ZsQMBsAorWCHYG/RZsiQWCxESOXywJC8YsnMkAV2yYCQBXbElAbAKK1gh2Bv0WbIGAyUREjmyECUkERI5sBYQsR4BsAorWCHYG/RZshskHhESOTAxARQWMzI2NTMUBgQjICQ1NCUmJjU0JCEyFhYVIzQmIyIGFRQhMxUjIgYBf7eZhq78jf79oP7z/r8BDnaCAS8BCZf6i/2jfJCqATO2v52jAZhlfoFegr5p6cT9VzGmYsXbabp3WXVzY9nIcP//AC3+SwX8BbAAJgDdAAAABwJUBG4AAP//ACH+SwUGBDoAJgDyAAAABwJUA3gAAAACAGcEbwLWBdcABQANACMAsAsvsATQsAQvsADQGbAALxiwCxCwB9CwBy+wAdCwAS8wMQETMxUDIwEzFRYXByY1AZNw0+Zd/tSxA0xQsASYAT8V/sEBVF97RkhavgD//wBHAgkCVALNAAYAEQAA//8ARwIJAlQCzQAGABEAAP//AJ4CbQSYAzEARgGv4ABMzUAA//8AggJtBdADMQBGAa+FAGZmQAAAAgAD/mADmQAAAAMABwAIALICBQMrMDEBITUhNSE1IQOZ/GoDlvxqA5b+YJ1nnAAAAQBjBCABlgYaAAgAHbIICQoREjkAsABFWLAALxuxACI+WbAE0LAELzAxARcGBxUjNTY2ARp8WwPVAWcGGk2FkJiKYNEAAAEAMwQAAWUGAAAIAB2yCAkKERI5ALAARViwBC8bsQQiPlmwANCwAC8wMRMnNjc1MxUUBq98WgPVaQQATYOSnopn0QAAAQAy/tYBZADKAAgAGbIICQoREjkAsAkvsQQNsAorWCHYG/RZMDETJzY3NTMVBgate1UD2gFm/tZOf5SThV3QAAEASgQAAXwGAAAIABYAsABFWLAILxuxCCI+WbAE0LAELzAxARUWFwcmJjU1AR8DWnxNaQYAno+GTT7RZ4r//wBsBCAC7wYaACYBhAkAAAcBhAFZAAD//wBABAACwAYAACYBhQ0AAAcBhQFbAAAAAgAy/sICqgD/AAkAEgAisgsTFBESObALELAF0ACwEy+xBA2wCitYIdgb9FmwDtAwMRMnNjc1MxUGBwYXJzY3NTMVFAaxf1UD2gE3Mfh/WATaZv7CTomdybpscmRBTo6Wy7Zj3QAAAQBAAAAEHgWwAAsATACwAEVYsAgvG7EIID5ZsABFWLAGLxuxBhw+WbAARViwCi8bsQocPlmwAEVYsAIvG7ECED5ZsAoQsQABsAorWCHYG/RZsATQsAXQMDEBIREjESE1IREzESEEHv6I8/6NAXPzAXgDcvyOA3LIAXb+igAAAQBc/mAEOQWwABMAfgCwAEVYsAwvG7EMID5ZsABFWLAKLxuxChw+WbAARViwDi8bsQ4cPlmwAEVYsAIvG7ECEj5ZsABFWLAALxuxABA+WbAARViwBC8bsQQQPlmxBgGwCitYIdgb9FmwDhCxCAGwCitYIdgb9FmwCdCwENCwEdCwBhCwEtCwE9AwMSEhESMRITUhESE1IREzESEVIREhBDn+iPP+jgFy/o4BcvMBeP6IAXj+YAGgwgK0xAF2/orE/UwAAAEAiAIGAkQD2wANABeyAw4PERI5ALADL7AKsAorWNgb3FkwMRM0NjMyFhUVFAYjIiYniHlkZ3h3Z2N5AgMDX3l5YiVed3Nd//8Aiv/1A28BAAAmABIDAAAHABIBzQAA//8Aiv/1BSgBAAAmABIDAAAnABIBzQAAAAcAEgOGAAAAAQBaAesBbQLtAAsAGbIDDA0REjkAsAMvsQkNsAorWCHYG/RZMDETNDYzMhYVFAYjIiZaSEFCSEhCQUgCazhKSjg3SUkAAAYASv/sB18FxAAVACMAJwA0AEEATgC8sihPUBESObAoELAC0LAoELAb0LAoELAm0LAoELA10LAoELBH0ACwJC+wJi+wAEVYsBkvG7EZID5ZsABFWLASLxuxEhA+WbAD0LADL7IFAxIREjmwB9CwBy+wEhCwDtCwDi+yEBIDERI5sBkQsCDQsCAvsBIQsSsCsAorWCHYG/RZsAMQsTICsAorWCHYG/RZsCsQsDjQsDIQsD/QsCAQsUUCsAorWCHYG/RZsBkQsUwCsAorWCHYG/RZMDEBNDYzMhc2MzIWFRUUBiMiJwYjIiY1ATQ2MzIWFRUUBiMiJjUBJwEXAxQWMzI2NTU0JiIGFQUUFjMyNjU1NCYiBhUBFBYzMjY1NTQmIgYVAy+siJZOTpWGr6mKl05OlIqs/RuohYqrq4iFqgF3fQLHfbBPPkBKTnxNAcdPPkBKTnxN+05NPz5MTX5LAWWCqm9vp4xHgapubqqGA3uDqqqJRoKpqYn8G0gEckj8OERXUkxLRlRUSkpEV1JMS0ZUVEoC6kVVVUlIRlZXSQAAAQBsAIoCMwOpAAYAEACwBS+yAgcFERI5sAIvMDEBEyMBNQEzATz3p/7gASCnAhn+cQGGEwGGAAABAFQAigIbA6kABgAQALAAL7IDBwAREjmwAy8wMRMBFQEjEwP7ASD+4Kf39wOp/noT/noBjwGQAAEALQBtA3EFJwADAAkAsAAvsAIvMDE3JwEXqn0Cx31tSARySAD//wA1ApsCvgWwAwcCIAAAApsAEwCwAEVYsAkvG7EJID5ZsA3QMDEAAAEAaQKMAv8FugAPAFSyChARERI5ALAARViwAC8bsQAgPlmwAEVYsAMvG7EDID5ZsABFWLANLxuxDRQ+WbAARViwBy8bsQcUPlmyAQMNERI5sAMQsQoDsAorWCHYG/RZMDEBFzYzIBERIxEmIyIHESMRAQEgS5ABA8UFfWMnxQWseYf+yf4JAdqtWf3SAyAAAAEAXwAABHwFwwAnAJKyHygpERI5ALAARViwFy8bsRcgPlmwAEVYsAYvG7EGED5ZsicGFxESObAnL7ENArAKK1gh2Bv0WbAB0LAGELEFAbAKK1gh2Bv0WbAJ0LAnELAQ0LAnELAj0LAjL7YPIx8jLyMDXbElArAKK1gh2Bv0WbAR0LAjELAU0LAXELEeAbAKK1gh2Bv0WbIbIx4REjkwMQEhFxQHIQchNTM2NjUnIzUzJyM1Myc0NiAWFSM0JiMiBhUXIRUhFyEDMv7QAkACuAH751InKwKloASclwX6AZbo9WlfWGcGAT/+xgUBNQHULodVysoJb1s3kXmQocrq2rhfaYJooZB5AAUAIQAABk8FsAAbAB8AIwAmACkAv7IKKisREjmwChCwH9CwChCwIdCwChCwJtCwChCwKNAAsABFWLAaLxuxGiA+WbAARViwFy8bsRcgPlmwAEVYsAwvG7EMED5ZsABFWLAJLxuxCRA+WbIFCRoREjmwBS+wAdCwAS+yDwEBXbEDA7AKK1gh2Bv0WbAFELEHA7AKK1gh2Bv0WbAl0LAK0LAO0LAFELAd0LAh0LAR0LADELAe0LAi0LAS0LABELAZ0LAn0LAV0LAJELAk0LAXELAp0DAxATMVIxUzFSMRIwEhESMRIzUzNSM1MxEzASERMwEzNSMFMycjATUjATMnBXfY2NjY/f7J/q3809PT0/wBNQFX+/5xlPP+Z+5fjwKML/2jKysDxaCXoP4SAe7+EgHuoJegAev+FQHr/N6Xl5f+fksB10QAAgCY/+wGOgWwAB4AJQCmsiEmJxESObAhELAQ0ACwAEVYsBUvG7EVID5ZsABFWLAZLxuxGRw+WbAARViwHS8bsR0cPlmwAEVYsAovG7EKED5ZsABFWLATLxuxExA+WbAdELEAAbAKK1gh2Bv0WbAKELEFAbAKK1gh2Bv0WbAAELAN0LAO0LIgExUREjmwIC+xEQGwCitYIdgb9FmwHRCwHNCwHC+wFRCxJAGwCitYIdgb9FkwMQEjERQWMzI3FQYjIBERIwYGByMRIxEhMhYXMxEzETMBMzIRNCcjBjO/Mj8mL1NN/uh4HPTKnvoBjNT9GHXyv/tfkvTmoAOG/aQ9OAq8FwE1AmWtuwP95QWww7MBB/75/q0BAPcGAP//AJT/7Ag8BbAAJgA2AAAABwBXBHIAAAAGACEAAAYHBbAAHwAjACcAKwAuADEA7LIqMjMREjmwKhCwDtCwKhCwItCwKhCwJ9CwKhCwLdCwKhCwMdAAsABFWLACLxuxAiA+WbAARViwDC8bsQwQPlmwAEVYsBAvG7EQED5ZsggCDBESObAIL7AE0LAEL7AA0LAEELEGA7AKK1gh2Bv0WbAIELEKA7AKK1gh2Bv0WbAO0LAKELAS0LAIELAU0LAGELAW0LAEELAY0LACELAa0LAEELAc0LACELAe0LAIELAg0LAGELAi0LAIELAk0LAGELAm0LAIELAo0LIqAgwREjmyLAIMERI5sAoQsC3Qsi8CDBESObAKELAw0DAxATMTMwMzFSMHMxUjAyMDIwMjAyM1MycjNTMDMxMzEzMBMzcjBTM3IwczJyMBNyMFNyMDwtM+/FCIqCHJ6nb5Xnxg+XfjwyGigU/7P9k94f49chqmAk5tGqHtSBoT/vIfPwJRHTsEKgGG/nqgoqD9uAJI/bgCSKCioAGG/noBhv04oqKioqL9+cW7uwAAAgB8AAAGEAQ6AA0AGwBtsggcHRESObAIELAQ0ACwAEVYsAAvG7EAHD5ZsABFWLAWLxuxFhw+WbAARViwCy8bsQsQPlmwAEVYsA4vG7EOED5ZsREBsAorWCHYG/RZsAAQsQkBsAorWCHYG/RZsgURCRESObIQCREREjkwMQEyFhcRIxE0JiMhESMRAREzESEyNjcRMxEGBiMDDLuuAvNaaf6u8wGZ8wFQalkB9AHv3AQ6wMv+tQFCbWP8igQ6+8YC1v3tYWgCrv1XvNUAAQBe/+0EMAXDACMAjrIVJCUREjkAsABFWLAWLxuxFiA+WbAARViwCS8bsQkQPlmyIxYJERI5sCMvsQACsAorWCHYG/RZsAkQsQQBsAorWCHYG/RZsAAQsAzQsCMQsA7QsCMQsBPQsBMvtg8THxMvEwNdsRACsAorWCHYG/RZsBYQsRsBsAorWCHYG/RZsBMQsB7QsBAQsCDQMDEBIRYWMzI3FwYjIAADIzUzNSM1MzYAMzIXByYjIgYHIRUhFSEDav6cBqOYbl8ceID/AP7aCKysrK0NASz9aoUcZmWXogkBY/6cAWQCD66sIcwdASABAo2Ajf8BGx/NIqykjYAAAAQAIQAABdQFsAAaAB8AJAApAOeyDCorERI5sAwQsBzQsAwQsCPQsAwQsCjQALAARViwCy8bsQsgPlmwAEVYsAEvG7EBED5ZsAsQsSQBsAorWCHYG/RZsCDQsCAvQBMAIBAgICAwIEAgUCBgIHAggCAJXbAe0LAeL7awHsAe0B4DXUALAB4QHiAeMB5AHgVdsSYDsAorWCHYG/RZsCfQsCcvQA8wJ0AnUCdgJ3AngCeQJwddsQABsAorWCHYG/RZsCYQsAPQsB4QsAbQsCAQsA/QsRIDsAorWCHYG/RZsBzQsB3QsAfQsCAQsArQsB4QsBTQsCYQsBfQMDEBESMRIzUzNSM1MxEhMgQXMxUjFwczFSMGBiMBJyEVISUhJichASEVITIB1v24uLi4Ai2tAQE85L0CAbzhNvq9ARUD/b4CQ/29AfBGcv7IAfT+DAExewId/eMDH6BIoAEJiIGgJiKgfYUBwihI6DsC/js3AAEAKAAABAwFsAAaAHCyFhscERI5ALAARViwGS8bsRkgPlmwAEVYsAwvG7EMED5ZsBkQsRgBsAorWCHYG/RZsAHQsBkQsBTQsBQvsAPQsBQQsRMHsAorWCHYG/RZsAbQsBQQsA7QsA4vsQkHsAorWCHYG/RZsg0JDhESOTAxASMWFzMHIwYGBwEVIQEnMzI2NyE3ISYjITchA9naMw/KMpcW3MkB0v7h/gMB/XCDFv3mMwHjMdj+8zYDrgT5S2W2pa8R/d8NAlGZXUy2m8wAAQAh/+wEUQWwAB4AlLIbHyAREjkAsABFWLARLxuxESA+WbAARViwBS8bsQUQPlmyExEFERI5sBMvsBfQsBcvsgAXAV2xGAGwCitYIdgb9FmwGdCwCNCwCdCwFxCwFtCwC9CwCtCwExCxFAGwCitYIdgb9FmwFdCwDNCwDdCwExCwEtCwD9CwDtCwBRCxGgGwCitYIdgb9FmyHgURERI5MDEBFQYCBCMiJxEHNTc1BzU3ETMVNxUHFTcVBxE2NjU1BFEClv7tsmuM3Nzc3Pzh4eHhqrIC/1nS/sOrFAJdV8dXiVfIVwE711rIWolayFn9+wL8+E0AAQBPAAAFDwQ6ABcAXbIAGBkREjkAsABFWLAXLxuxFxw+WbAARViwEC8bsRAQPlmwAEVYsAsvG7ELED5ZsABFWLAFLxuxBRA+WbIVCxcREjmwFS+wANCwFRCxDAGwCitYIdgb9FmwCdAwMQEWABMVIzUmJicRIxEGBhUVIzUSADc1MwMo4AEDBPMBgXLzcYLzAwEE3/MDain+kv7sv7jF7yr9agKVKvPHsboBFAFwK9EAAAIAKAAABTMFsAAWAB8Ae7IYICEREjmwGBCwDdAAsABFWLAMLxuxDCA+WbAARViwAi8bsQIQPlmyBgIMERI5sAYvsQUBsAorWCHYG/RZsAHQsAYQsArQsAovsg8KAV2xCQGwCitYIdgb9FmwFNCwBhCwFdCwChCwF9CwDBCxHwGwCitYIdgb9FkwMSUhFSM1IzUzNSM1MxEhMgQVFAQHIRUhASEyNjU0JichAzP+vvzNzc3NAi3xASD+7vT+xAFC/r4BLYiQjXz+xOfn58trywLI+9DU8QNrATZ+fXCOAwAABABw/+wFiQXFABkAJgA0ADgAmLIaOToREjmwGhCwANCwGhCwJ9CwGhCwN9AAsDUvsDcvsABFWLAJLxuxCSA+WbAARViwJC8bsSQQPlmwCRCwA9CwAy+yDQkDERI5sAkQsRACsAorWCHYG/RZsAMQsRcCsAorWCHYG/RZshkDCRESObAkELAd0LAdL7AkELEqArAKK1gh2Bv0WbAdELExArAKK1gh2Bv0WTAxARQGICY1NTQ2MzIWFSM0JiMiBhUVFBYyNjUBNDYzMhYVFRQGICY1FxQWMzI2NTU0JiMiBhUFJwEXArGf/wCinoKAoapBNjRCQ2pAARiuh4itp/7oq6pPPkBJTj0+Tf37fgLHfgQlc5KnikeCq5RzNUBUSkpFVUMx/UCGpqaNR4Kpp4kFRFdTS0tGVFRK9EgEckgAAgBM/+sDkAX5ABcAIQBdsgEiIxESObABELAY0ACwDC+wAEVYsAAvG7EAED5ZsgYMABESObAGL7EFB7AKK1gh2Bv0WbAT0LAAELEXAbAKK1gh2Bv0WbAGELAY0LAMELEfAbAKK1gh2Bv0WTAxBSImNQYjNTI3ETY2MzIWFRUUAgcVFBYzAzY2NTU0JiMiBwLb4e1hYGFgA7KaiKzXsmhs1E1XKyBWAxXr5RO7GAHpv9a0myat/qlnTY56AkRLzGYpP0CyAAQAkAAAB8IFwAADAA8AHQAnAKmyHigpERI5sB4QsAHQsB4QsATQsB4QsBDQALAARViwJi8bsSYgPlmwAEVYsCQvG7EkID5ZsABFWLAGLxuxBiA+WbAARViwIS8bsSEQPlmwAEVYsB8vG7EfED5ZsAYQsA3QsA0vsALQsAIvsgACAV2xAQKwCitYIdgb9FmwDRCxEwKwCitYIdgb9FmwBhCxGgKwCitYIdgb9FmyICQhERI5siUfJhESOTAxASE1IQE0NiAWFRUUBiAmNRcUFjMyNjU1NCYjIgYVASEBESMRIQERMweX/Z8CYf12vgE4v7r+wr2vXFFPW1xQT1z+x/70/g30AQsB9vIBnJUCL5/BwKZOnMLCogZgbGxjUV9tbWL7owQK+/YFsPvzBA0AAgBtA5QEVwWwAAwAFABuALAARViwBi8bsQYgPlmwAEVYsAkvG7EJID5ZsABFWLATLxuxEyA+WbIBFQYREjmwAS+yAAkBERI5sgMBBhESObAE0LIIAQkREjmwARCwC9CwBhCwDbAKK1jYG9xZsAEQsA/QsA0QsBHQsBLQMDEBAyMDESMRMxMTMxEjASMRIxEjNSED6Hw+fG+JgYWFb/4RinWNAYwFCf6LAXT+jAIc/oMBff3kAb3+RQG7XwACAJb/7ASRBE4AFQAcAGWyAh0eERI5sAIQsBbQALAARViwCi8bsQocPlmwAEVYsAIvG7ECED5ZshkKAhESObAZL7EPCrAKK1gh2Bv0WbACELETDLAKK1gh2Bv0WbIVCgIREjmwChCxFgqwCitYIdgb9FkwMSUGIyImAjU0EjYzMhYWFxUhERYzMjcBIgcRIREmBBS3u5H0h5D4hIXjhAP9AHeaxKz+kJd6AhxzXnKdAQGTjwEDn4vzkD7+uG56Ayp6/usBHnEA//8AWf/1BcsFmQAnAcb/2QKGACcBlAD7AAABBwIkAyEAAAAQALAARViwBi8bsQYgPlkwMf//AFT/9QZoBbQAJwIfAB0ClAAnAZQBqAAAAQcCJAO+AAAAEACwAEVYsA0vG7ENID5ZMDH//wBb//UGXAWoACcCIQAMApMAJwGUAYwAAAEHAiQDsgAAABAAsABFWLABLxuxASA+WTAx//8AWP/1BhoFowAnAiMAIgKOACcBlAEzAAABBwIkA3AAAAAQALAARViwBS8bsQUgPlkwMQACAGL/6wRDBfUAGQAmAF6yEycoERI5sBMQsCDQALALL7AARViwEy8bsRMQPlmyAAsTERI5sAAvsgILExESObALELEFAbAKK1gh2Bv0WbAAELEaAbAKK1gh2Bv0WbATELEgAbAKK1gh2Bv0WTAxATIXJiYjIgcnNzYzIAARFRQCBiMiADU1NBIXIgYVFBYzMjY1NSYmAjiudxrFhHyLHTxujwENASd645Tj/vP+9HuFhHp5hRaLBAR9wuU1txks/k7+cjXB/tOnAST3Dd8BEsKnpJqw0MVVTF8AAAEApv8bBPQFsAAHACgAsAQvsABFWLAGLxuxBiA+WbAEELAB0LAGELECAbAKK1gh2Bv0WTAxBSMRIREjESEE9PT9mfMETuUF1PosBpUAAAEAQP7zBMEFsAAMADcAsAMvsABFWLAILxuxCCA+WbADELECAbAKK1gh2Bv0WbAF0LAIELEKAbAKK1gh2Bv0WbAH0DAxAQEhFSE1AQE1IRUhAQOP/e4DRPt/Ak/9sQRH/PYCEgJD/XPDlwLIAsaYw/1zAAEAngJtA+8DMQADABIAsAIvsQEBsAorWCHYG/RZMDEBITUhA+/8rwNRAm3EAAABADsAAASSBbAACAA9sgAJChESOQCwBy+wAEVYsAEvG7EBID5ZsABFWLADLxuxAxA+WbIAAQMREjmwBxCxBgGwCitYIdgb9FkwMQEBMwEjAyM1IQJBAXjZ/hfF2NEBZwErBIX6UAJBxQAAAwBe/+wH3wROABoAKgA5AHSyBzo7ERI5sAcQsCLQsAcQsDLQALAARViwBC8bsQQQPlmwAEVYsAkvG7EJED5ZsAQQsBbQsBYvsgcWBBESObAS0LASL7IUFgQREjmwFhCxHgGwCitYIdgb9FmwBBCxJwGwCitYIdgb9FmwLtCwHhCwN9AwMQEUBgYjIiYnAiEiJiY1NTQSNjMgExIhMhYWFwc0JiMiBwYHFRYXFjMyNjUFFBYzMjY3NzUmJyYjIgYH34DmkI3pVar+34/lgYHkjgEkqakBJI7kgQHvknqkbigPDy5rn3mV+l2Se2msKwcPKG6keZICEZj9kKOn/raO/5kVmAEAj/65AUeP/ZcEmsbJSkIkRVXDw6IFncOzkBokQkrJwwAAAf+v/ksCqAYVABUAP7ICFhcREjkAsABFWLAOLxuxDiI+WbAARViwAy8bsQMSPlmxCAGwCitYIdgb9FmwDhCxEwGwCitYIdgb9FkwMQUUBiMiJzcWMzI3ETQ2MzIXByYjIhUBkLaqQj8SLCWKAsCyP1kZKjKjT7C2E70NnQT0s8MVuQu4AAACAGUBAQQVA/oAFQArAHyyECwtERI5sBAQsBzQALAZL7AD0LADL7AI0LAIL7ADELAK0LAIELENAbAKK1gh2Bv0WbADELESAbAKK1gh2Bv0WbANELAV0LAZELAe0LAeL7AZELAg0LAeELEjAbAKK1gh2Bv0WbAZELEoAbAKK1gh2Bv0WbAjELAr0DAxEzY2MzYXFxYzMjcVBiMiJycmByIGBxU2NjM2FxcWMzI3FQYjIicnJgciBgdlMIRCUkycRlGEZWZ/UUaYT1RChzAwgEJUT5hGUYdlZoNRRpxMUkKEMAOOMjgCIk4gftlqIEwkAkI8yzI4AiRMIH7ZaiBOIgJCPAABAJEAgAPvBMMAEwA5ALATL7EAAbAKK1gh2Bv0WbAE0LATELAH0LATELAP0LAPL7EQAbAKK1gh2Bv0WbAI0LAPELAL0DAxASEHJzcjNSE3ITUhNxcHMxUhByED7/3igG1dsAEhfv5hAhCGbmO9/tF9AawBZOQ+psnfyu0+r8rf//8APAAUA40EawBnACAAAACLQAA5mgAHAa//nv2n//8AgAAUA+AEawBnACIAAACLQAA5mgAHAa//4v2nAAIAJAAAA+sFsAAFAAkAOLIGCgsREjmwBhCwBNAAsABFWLAALxuxACA+WbAARViwAy8bsQMQPlmyBgADERI5sggAAxESOTAxATMBASMBAQMTEwGkxAGD/oDF/n4B4e3y7AWw/Sf9KQLXAdb+Kv4pAdcA//8AoQCrAbwFBwAnABIAGgC2AAcAEgAaBAcAAgBjAn8CPgQ5AAMABwA0sgAICRESObAF0ACwAEVYsAIvG7ECHD5ZsABFWLAGLxuxBhw+WbIACAIREjmwAC+wBNAwMQEjETMBIxEzAQCdnQE+nZ0CfwG6/kYBugABAEX/ZwFaAQYACAAMALAEL7AA0LAALzAxFyc2NzUzFQYGxYBJA8kBU5lNc3tkT126//8ALQAABRoGFQAmAEoAAAAHAEoCRAAAAAIAGAAABBcGFQAXABsAdbIJHB0REjmwCRCwGdAAsABFWLAJLxuxCSI+WbAARViwBC8bsQQcPlmwAEVYsBovG7EaHD5ZsABFWLAXLxuxFxA+WbAARViwGS8bsRkQPlmwBBCwE9CxFgGwCitYIdgb9FmwAdCwCRCxDwGwCitYIdgb9FkwMTMRIzUzNT4CMzIWFwcmIyIGFRUzFSMRISMRM72lpQFqwohQk08linJvZNXVAmfz8wOGtEp/tlwiGskwYWFEtPx6BDoAAQAtAAAELAYVABYAZbISFxgREjkAsABFWLASLxuxEiI+WbAARViwDi8bsQ4cPlmwAEVYsAkvG7EJED5ZsABFWLAWLxuxFhA+WbASELECAbAKK1gh2Bv0WbAOELAF0LAOELELAbAKK1gh2Bv0WbAI0DAxASYjIhUVMxUjESMRIzUzNTY2MzIFESMDOWZKxNzc86WlAdfEegFE8wU/DrhbtPx6A4a0YbfDMPobAAIALQAABpMGFQAoACwAuLIULS4REjmwFBCwKtAAsABFWLAILxuxCCI+WbAARViwFi8bsRYiPlmwAEVYsCsvG7ErHD5ZsABFWLAhLxuxIRw+WbAARViwES8bsREcPlmwAEVYsAQvG7EEHD5ZsABFWLAoLxuxKBA+WbAARViwJS8bsSUQPlmwAEVYsCovG7EqED5ZsCEQsSIBsAorWCHYG/RZsCbQsAHQsAgQsQ0BsAorWCHYG/RZsBYQsRwBsAorWCHYG/RZMDEzESM1MzU0NjMyFwcmIyIVFSE1PgIzMhYXByYjIgYVFTMVIxEjESERISMRM9Klpci0QEgGKDWuAXQBasKIUJNPJohzb2TV1fP+jATO8/MDhrRjtMQSvgizYEp/tlwiGskwYWFEtPx6A4b8egQ6AAABAC0AAAaTBhUAJwCoshMoKRESOQCwAEVYsBUvG7EVIj5ZsABFWLAILxuxCCI+WbAARViwBC8bsQQcPlmwAEVYsBAvG7EQHD5ZsABFWLAfLxuxHxw+WbAARViwJy8bsScQPlmwAEVYsCQvG7EkED5ZsABFWLAZLxuxGRA+WbAEELEBAbAKK1gh2Bv0WbAIELENAbAKK1gh2Bv0WbAVELEcAbAKK1gh2Bv0WbABELAm0LAi0DAxMxEjNTM1NDYzMhcHJiMiFRUhNTY2MzIFESMRJiMiFRUzFSMRIxEhEdKlpci0QEgGKDWuAXQB18R6AUTzZkrE3Nzz/owDhrRjtMQSvgizYGG3wzD6GwU/DrhbtPx6A4b8egAAAQAt/+wE0QYVACQAfbITJSYREjkAsABFWLAbLxuxGxw+WbAARViwHy8bsR8iPlmwAEVYsBYvG7EWED5ZsABFWLAKLxuxChA+WbAbELEYAbAKK1gh2Bv0WbAO0LAB0LAKELEFAbAKK1gh2Bv0WbAbELAP0LAfELETAbAKK1gh2Bv0WbAPELAj0DAxASMRFBYzMjcVBiMgEREjNTM1JiMiFREjESM1MzU0NjMyFhcRMwTLvzE/Ji9TTf7osrJFbKPzpaXCsGXxcr8Dhv2kPjcKvBcBNQJltPgguftnA4a0YrbDODH+jgABAEv/7AaABhgATADIskZNThESOQCwAEVYsEcvG7FHIj5ZsABFWLBALxuxQBw+WbAARViwDy8bsQ8cPlmwAEVYsEsvG7FLHD5ZsABFWLAJLxuxCRA+WbAARViwLC8bsSwQPlmwSxCxAAGwCitYIdgb9FmwCRCxBAGwCitYIdgb9FmwABCwDdCwDtCwRxCxFAewCitYIdgb9FmyHUAsERI5sEAQsSAHsAorWCHYG/RZsiYsQBESObIxLEAREjmwLBCxNAewCitYIdgb9FmyO0AsERI5MDEBIxEUMzI3FQYjIiYnESM1MzU0JiMiBhUUHgIVIzQmIyIGFRQWBBYWFRQGIyImJjUzFhYzMjY1NCYmJyY1NDYzMhcmNTQ2MzIWFRUzBnm/cSYvU02HkAGsrGBYT1gdIRz0aFZQZV4BHqNP8sSF0HTsBXhjYGRr+FO27LZbTS3ZrsnevwOG/beICrwXqqICTrRYYmlURTppZnlNRl1KPjg+P1d6V5K1YKhhVl1JO0FENChYp4y8F2xPgaXKxU8AABYAWf5yB+wFrgANABoAKAA3AD0AQwBJAE8AVgBaAF4AYgBmAGoAbgB2AHoAfgCCAIYAigCOAciyEI+QERI5sBAQsADQsBAQsBvQsBAQsDDQsBAQsDzQsBAQsD7QsBAQsEbQsBAQsErQsBAQsFDQsBAQsFfQsBAQsFvQsBAQsGHQsBAQsGPQsBAQsGfQsBAQsG3QsBAQsHDQsBAQsHfQsBAQsHvQsBAQsH/QsBAQsITQsBAQsIjQsBAQsIzQALA9L7AARViwRi8bsUYgPlmyfUQDK7J8eQMrsniBAyuygDkDK7IKRj0REjmwCi+wA9CwAy+wDtCwDi+wChCwD9CwDy+ybw4PERI5fLBvLxixUAuwCitYIdgb9FmyFVBvERI5sAoQsR4LsAorWCHYG/RZsAMQsSULsAorWCHYG/RZsA8QsCnQsCkvsA4QsC7QsC4vsTQLsAorWCHYG/RZsD0QsGvQsGfQsGPQsD7QsT8MsAorWCHYG/RZsGXQsGnQsG3QsDzQsDkQsEHQsEYQsUcMsAorWCHYG/RZsFvQsFfQsErQsEYQsGDQsFzQsFjQsEvQsEQQsE7QsA4QsVELsAorWCHYG/RZsEcQsF/QsA8QsXYLsAorWCHYG/RZsHgQsITQsHkQsIXQsHwQsIjQsH0QsInQsIAQsIzQsIEQsI3QMDEBFAYjIiYnNTQ2MzIWFxMRMzIWFRQHFhYVFCMBNCYjIgYVFRQWMzI2NQEzERQGIyImNTMUMzI2NQERMxUzFSE1MzUzEQERIRUjFSU1IREjNQEVMzI1NCcTNSEVITUhFSE1IRUBNSEVITUhFSE1IRUTMzI1NCYjIwEjNTM1IzUzESM1MyUjNTM1IzUzESM1MwM3gWRmgAJ+aGWAAkO8YnJUMjTQ/o9KQUBKSkJASQO6XGlSWG1daCk2+cRxxAUox2/4bQE1xAXsATZv/Fx+Z2LLARb9WwEV/VwBFAIKARb9WwEV/VwBFLxddjo8XfzxcXFxcXFxByJvb29vb28B1GJ5eF51X3x4Xv6zAiVJTVQgDUYtmwFIRU5ORXBFTk5FAU/+hk5dUVNbNiz8yQE7ynFxyv7FBh8BHXSpqXT+46n8tqlTUgQDSnR0dHR0dPk4cXFxcXFxA8RQKR7+0/x++vwV+X78fvr8FfkABQBc/dUH1whzAAMAHAAgACQAKABMALAhL7AlL7AA0LAAL7AhELAC0LACL7IgAgAREjmwIC+wHdCwHS+wBNCwBC+yDQACERI5sA0vsBTQsBQvsgcEFBESObIZFAQREjkwMQkDBTQ2NzY2NTQmIyIGBzM2NjMyFhUUBwYGFRcjFTMDMxUjAzMVIwQYA7/8QfxEBA8eJEpcp5WQoALLAjorOThdWy/KyspLBAQCBAQGUvwx/DEDz/E6Ohgnh0qAl4t/MzRANF88QVxMW6r9TAQKngQAAQA8AAACsgMgABcAW7IIGBkREjkAsABFWLAPLxuxDxo+WbAARViwAC8bsQAQPlmxFgKwCitYIdgb9FmyAhYAERI5sgMPABESObAPELEIArAKK1gh2Bv0WbIMAA8REjmyFQAPERI5MDEhITUBNjU0JiMiBhUjNDYzMhYVFA8CIQKy/ZwBHXE2NDpCuqmHj5xqYowBc30BBWdDKjVCNnSZgHNrZldxAAEAgAAAAgIDEwAGADIAsABFWLAFLxuxBRo+WbAARViwAS8bsQEQPlmwBRCwBNCwBC+xAwKwCitYIdgb9FkwMSEjEQc1JTMCArnJAW8TAjowkncAAAIAS//1AqoDIAANABcASLIDGBkREjmwAxCwENAAsABFWLAKLxuxCho+WbAARViwAy8bsQMQPlmwChCxEAKwCitYIdgb9FmwAxCxFQKwCitYIdgb9FkwMQEUBiMiJjU1NDYzMhYVJzQjIgcVFDMyNwKqnpCSn56RkKC7dXIDd28EAT6fqqqemJ2urZ4MqZ+4qZoAAgBP//YDtwSdABQAIQBgshUiIxESObAVELAI0ACwAEVYsAgvG7EIHj5ZsABFWLAPLxuxDxA+WbIVCA8REjl8sBUvGLECAbAKK1gh2Bv0WbAPELERAbAKK1gh2Bv0WbAIELEcAbAKK1gh2Bv0WTAxAQYjIiY1NDYzMhYVFRAABSM1MzY2JzI2NzU0JiMiBhUUFgLBZJGzyvLAzuj+wP7FJBjBwK1EZBhqWVhpaQHVW8+2suz+5UH+w/6+BMEBjO06KlltfnteX3AAAAMAWP/wA8MEnQAXACIALQCBsgkuLxESObAJELAg0LAJELAm0ACwAEVYsBUvG7EVHj5ZsABFWLAJLxuxCRA+WbIrCRUREjmwKy+yzysBcbI/KwFxsl8rAXKxGwGwCitYIdgb9FmyAxsrERI5sg8rGxESObAJELEgAbAKK1gh2Bv0WbAVELEmAbAKK1gh2Bv0WTAxARQGBxYWFRQGIyImNTQ2NyYmNTQ2MzIWAzQmIyIGFBYzMjYDNCYjIgYVFBYyNgOmXFFebO7HxvBsXlFc3rm64NZrWVhpaVpYahxaTk1XWJxYA1ZVgycoj2GbtLOcYo8oJ4JVmK+u/WNKVlWWVVUCQkJPTURDUVEAAQA5AAAD0ASNAAYAOrIBBwgREjkAsABFWLAFLxuxBR4+WbAARViwAS8bsQEQPlmwBRCxAwGwCitYIdgb9FmyAAMFERI5MDEBASEBITUhA9D9/v8AAgL9aQOXBAX7+wPJxAACAGD/8APXBJoAEwAgAGWyGyEiERI5sBsQsAzQALAARViwAC8bsQAePlmwAEVYsAwvG7EMED5ZsAAQsQEBsAorWCHYG/RZsgYADBESObAGL7IEBgwREjmxFAGwCitYIdgb9FmwDBCxGwGwCitYIdgb9FkwMQEVIgYHNjMyFhUUBiMiJjU1EAAlAyIGBxUUFjMyNjU0JgMT2tIRa6GtyO7E0PUBTQE4xEhsGm5fWW1pBJrHnZ1t1LKv4fneSAE3AVAE/ao9LS50hnNZW2sAAAEAZ//wA9EEjQAdAG2yGh4fERI5ALAARViwAS8bsQEePlmwAEVYsA0vG7ENED5ZsAEQsQMBsAorWCHYG/RZsgcBDRESObAHL7EaAbAKK1gh2Bv0WbIFGgcREjmwDRCxFAGwCitYIdgb9FmyERQaERI5sh0aFBESOTAxExMhFSEHNjMyFhUUBiMiJiczFhYzMjY1NCYjIgcHiEkCw/4GIWRludbpy7X6B+4IbFRaaHZkXjwiAjsCUsjzK8u1sdy7lUpEamRdbScXAAACADAAAAPsBI0ACgAOAFeyDg8QERI5sA4QsAnQALAARViwCS8bsQkePlmwAEVYsAQvG7EEED5ZsgEJBBESObABL7ECAbAKK1gh2Bv0WbAG0LIIBgEREjmwARCwC9CyDQkEERI5MDEBMxUjFSM1IScBMwEhEQcDUpqa8/3bCgIq+P3SATsUAbzE+PibAvr9LwGaIQAAAQA+//ADvASdACYAobIgJygREjkAsABFWLAOLxuxDh4+WbAARViwGS8bsRkQPlmyAQ4ZERI5sAEvsj8BAXGyzwEBcbJfAQFyso8BAXKy/wEBcbIPAQFytG8BfwECcbSvAb8BAl2yvwEBcrAOELEHAbAKK1gh2Bv0WbIKDhkREjmwARCxJQGwCitYIdgb9FmyFCUBERI5sh0ZDhESObAZELEgAbAKK1gh2Bv0WTAxATMyNjU0JiMiBhUjNDYzMhYVFAYHFhUUBiMiJjUzFBYzMjY1NCMjAWeAaWViWVJo8++6y+djYdj8ysXz9HJaY2jlfQKpV0ZHTUg6kbSxnE+GJT3Tnbm5nkJTWEioAAEAQgAAA9cEnQAYAFuyCBkaERI5ALAARViwDy8bsQ8ePlmwAEVYsAAvG7EAED5ZsRcBsAorWCHYG/RZsgIXABESObIDDwAREjmwDxCxCAGwCitYIdgb9FmyCwAPERI5shUADxESOTAxISE1ATY1NCYjIgYVIzQ2MzIWFRQGBwcFIQPX/IUBqbFgT2Nu9PfJxeJSZmD/AAJGpQGOnG5HVmVbqdq7olKaZFvTAAABAJYAAALEBI0ABgBAsgEHCBESOQCwAEVYsAUvG7EFHj5ZsABFWLAALxuxABA+WbAFELAE0LAEL7EDAbAKK1gh2Bv0WbICAwUREjkwMSEjEQU1JTMCxPP+xQISHANvU8OuAAIAWf/wA8MEnQANABcASLIDGBkREjmwAxCwENAAsABFWLAKLxuxCh4+WbAARViwAy8bsQMQPlmwChCxEAGwCitYIdgb9FmwAxCxFQGwCitYIdgb9FkwMQEUAiMiJic1NBIzMhIXJxAjIgMREDMyEwPD49HM5wPi0tHkAfTCvQXEugYB4fD+//jt1u8BA/8A7xQBF/75/vr+5gEGAAEAQQAAA/MEjQAJAEYAsABFWLAHLxuxBx4+WbAARViwAi8bsQIQPlmxAAGwCitYIdgb9FmyBAACERI5sAcQsQUBsAorWCHYG/RZsgkFBxESOTAxJSEVITUBITUhFQF4Anv8TgJs/ZUDoMLCjQM8xIoAAAEABQAABDYEjQAIADEAsABFWLABLxuxAR4+WbAARViwBy8bsQcePlmwAEVYsAQvG7EEED5ZsgABBBESOTAxAQEhAREjEQEhAh0BDgEL/l3y/mQBCwJ6AhP9B/5sAaEC7AAAAQAVAAAESgSNAAsAUwCwAEVYsAEvG7EBHj5ZsABFWLAKLxuxCh4+WbAARViwBC8bsQQQPlmwAEVYsAcvG7EHED5ZsgABBBESObIGAQQREjmyAwAGERI5sgkGABESOTAxARMhAQEhAwMhAQEhAifyARz+iQGM/uD/+v7kAYH+iAEaAvoBk/2+/bUBmf5nAksCQgABACgAAAXlBI0ADABZALAARViwAS8bsQEePlmwAEVYsAgvG7EIHj5ZsABFWLALLxuxCx4+WbAARViwAy8bsQMQPlmwAEVYsAYvG7EGED5ZsgABAxESObIFAQMREjmyCgEDERI5MDEBEzMBIwMDIwEzExMzBEqv7P7m69jb6/7m7LHY1gErA2L7cwNB/L8EjfycA2QAAQAJAAAEcgSNAAgAMQCwAEVYsAMvG7EDHj5ZsABFWLAHLxuxBx4+WbAARViwBS8bsQUQPlmyAQMFERI5MDEBFzcBIQEjASECKhMSASIBAf5G9v5HAQEBOE1LA1f7cwSNAAABAGf/8AQeBI0ADwA2sgwQERESOQCwAEVYsAgvG7EIHj5ZsABFWLAELxuxBBA+WbEMAbAKK1gh2Bv0WbAIELAP0DAxAREUBCAkNREzERQWMzI3EQQe/v/+Sv8A8X5s5QQEjf0BvuDdwQL//QBzaNQDBwABACQAAAQWBI0ABwAvALAARViwBi8bsQYePlmwAEVYsAIvG7ECED5ZsAYQsQABsAorWCHYG/RZsATQMDEBIREjESE1IQQW/n7z/oMD8gPJ/DcDycQAAAEAPv/wA+8EnQAlAGayCSYnERI5ALAARViwCS8bsQkePlmwAEVYsBwvG7EcED5ZsgMcCRESObINCRwREjmwCRCxEAGwCitYIdgb9FmwAxCxFQGwCitYIdgb9FmyIRwJERI5sBwQsSMBsAorWCHYG/RZMDEBNCYkJiY1NDYzMhYVIzQmIyIGFRQWFxYWFRQGIyImJjUzFCEyNgMCaP7PsFP2w9L+83hlX25xj93A+MyK5X70AQBhbwEyQk9MYoNckrvIoFFdTUA6TCM2so6Zrl2qccBKAAACAHYAAAQ5BI0ADQAWAGOyBRcYERI5sAUQsA/QALAARViwBC8bsQQePlmwAEVYsAIvG7ECED5ZsABFWLANLxuxDRA+WbIOAgQREjmwDi+xAAGwCitYIdgb9FmyCgAOERI5sAQQsRUBsAorWCHYG/RZMDEBIxEjESEyFhUUBwEVIQEzMjY1NCYjIwJI3/MByNrw4QES/vz+NNVsbGlv1QGp/lcEjbeq61v+JQsCa19OUWAAAgBM/zAEbASdABQAIgBIsggjJBESObAIELAf0ACwAEVYsBEvG7ERHj5ZsABFWLAILxuxCBA+WbARELEYAbAKK1gh2Bv0WbAIELEfAbAKK1gh2Bv0WTAxARQGBxcHJQYjIiYCJzU0EjYzMgARJzQmIyIGFRUUFjMyNjUEbG5jz53+9jI0mvKEAYLxnO8BIvGXiYaXl4iJlQIso/FImIjJCYsBAao5qwEFjv7I/vQIt8DDtjOwycO2AAIAdgAABCwEjQAKABMAT7IEFBUREjmwBBCwDNAAsABFWLADLxuxAx4+WbAARViwAS8bsQEQPlmyCwEDERI5sAsvsQABsAorWCHYG/RZsAMQsRIBsAorWCHYG/RZMDEBESMRITIWFRQGByczMjY1NCYjIwFp8wHl1P3x1P7yaHd5ZfMBmf5nBI3VranGA8RYVFdpAAACAE//8ARvBJ0ADgAcAEiyAx0eERI5sAMQsBLQALAARViwCy8bsQsePlmwAEVYsAMvG7EDED5ZsAsQsRIBsAorWCHYG/RZsAMQsRkBsAorWCHYG/RZMDEBEAAjIgARNTQSNjMyABEnNCYjIgYVFRQWMzI2NQRv/t/t7P7ahfCb8AEg8paIhpiZh4iUAiz++P7MATUBDC6sAQeL/sf+9Qi3wMC3NbLHw7YAAAEAdgAABGcEjQAJAEUAsABFWLAFLxuxBR4+WbAARViwCC8bsQgePlmwAEVYsAAvG7EAED5ZsABFWLADLxuxAxA+WbICBQAREjmyBwUAERI5MDEhIwERIxEzAREzBGfy/fTz8wIM8gMb/OUEjfzkAxwAAAEAdgAABY8EjQAOAGCyAQ8QERI5ALAARViwAC8bsQAePlmwAEVYsAIvG7ECHj5ZsABFWLAELxuxBBA+WbAARViwCC8bsQgQPlmwAEVYsAwvG7EMED5ZsgEABBESObIHAAQREjmyCgAEERI5MDEJAiERIxETASMBExEjEQGyAVEBTgE+8hn+oKj+oRnyBI38tQNL+3MBOwI6/IsDcP3L/sUEjQAAAQB2AAADlASNAAUAKQCwAEVYsAQvG7EEHj5ZsABFWLACLxuxAhA+WbEAAbAKK1gh2Bv0WTAxJSEVIREzAWkCK/zi88LCBI0AAQB2AAAEaASNAAwASwCwAEVYsAQvG7EEHj5ZsABFWLAILxuxCB4+WbAARViwAi8bsQIQPlmwAEVYsAsvG7ELED5ZsgYCBBESObAGELAB0LIKAQYREjkwMQEHESMRMxE3ASEBASEB8Ifz824BTwEs/kMB0/7eAduD/qgEjf39hgF9/ff9fAABACT/8ANkBI0ADgAjsgUPEBESOQCwAEVYsAUvG7EFED5ZsQsBsAorWCHYG/RZMDEBMxEUBiMiJjUzFDMyNjUCcfPjssrh9LdLVwSN/OCuz8CvrV5dAAEAhQAAAXcEjQADAB0AsABFWLACLxuxAh4+WbAARViwAC8bsQAQPlkwMSEjETMBd/LyBI0AAAEAdgAABGgEjQALAIcAsABFWLAGLxuxBh4+WbAARViwCi8bsQoePlmwAEVYsAAvG7EAED5ZsABFWLAELxuxBBA+WbIJBgAREjmwCS+0rwm/CQJdsj8JAXGyzwkBcbI/CQFysv8JAXGyDwkBcrRvCX8JAnG03wnvCQJdsl8JAXK0HAksCQJdsQIBsAorWCHYG/RZMDEhIxEhESMRMxEhETMEaPP99PPzAgzzAdv+JQSN/hEB7wAAAQBU//AESASdABwAX7IaHR4REjkAsABFWLAKLxuxCh4+WbAARViwAy8bsQMQPlmyDgMKERI5sAoQsREBsAorWCHYG/RZsAMQsRcBsAorWCHYG/RZshsDChESObAbL7EZB7AKK1gh2Bv0WTAxJQcGISIAETUQADMyFhcjJiYjIBEVFBYgNzUjNSEESBeW/tX4/twBFvTX+hntEnls/uSgAShG+QHrkxiLAS4BCUEBCQEsw8BkXP6JQLe6OcixAAEAdgAAA54EjQAJAEIAsABFWLAELxuxBB4+WbAARViwAi8bsQIQPlmyCQQCERI5sAkvsQABsAorWCHYG/RZsAQQsQYBsAorWCHYG/RZMDEBIREjESEVIREhA1v+DvMDKP3LAfIB2/4lBI3E/tUAAQA+/xMD7wVzACoAcrITKywREjkAsABFWLAJLxuxCR4+WbAARViwIi8bsSIQPlmyAyIJERI5sAkQsAzQsAMQsRgBsAorWCHYG/RZsAkQsRMBsAorWCHYG/RZshAYExESObAiELAf0LAiELEoAbAKK1gh2Bv0WbImAygREjkwMQE0JiQmJjU0Njc1MxUWFhUjNCYjIgYVFBYXFhYVFAYHFSM1JiY1MxQhMjYDAmj+z7BTz6mgpsvzeGVfbnGP3cDDrqC94/QBAGFvATJCT0xig1yGtBDZ3BXAjVFdTUA6TCM2so6GrBHh4RPHmsBKAAEAOAAABBoEnQAfAHGyGyAhERI5ALAARViwEy8bsRMePlmwAEVYsAUvG7EFED5Zsh8TBRESObAfL7EAArAKK1gh2Bv0WbAFELEDAbAKK1gh2Bv0WbAH0LAI0LAAELAM0LAfELAO0LATELEaAbAKK1gh2Bv0WbIXHxoREjkwMQEhFgchByE1MzY2JycjNTMnJjYzMhYVIzQmIyIGFxchA0f+hQZQApgB/GUKKSsDAaCbAwbYv8LZ81dQTVcFBAGAAeWycMPDC5N9B5Npzu7UvGFqfnlpAAABAAkAAAOZBI0AGABvsgAZGhESOQCwAEVYsAEvG7EBHj5ZsABFWLAMLxuxDBA+WbIADAEREjmyCAEMERI5sAgvsAPQfLADLxiwBbAKK1jYG9xZsAgQsAqwCitY2BvcWbAO0LAIELAQ0LAFELAT0LADELAV0LABELAX0DAxARMzATMVIQcVIRUhFSM1ITUhNSchNTMBIQHSyP/++r/+/woBC/718v70AQwE/vjG/voBAQKOAf/9t5MXMJHZ2ZE+CZMCSQAAAQB2AAADlwSNAAUAM7IBBgcREjkAsABFWLAELxuxBB4+WbAARViwAy8bsQMQPlmwBBCxAAGwCitYIdgb9FkwMQEhESMRIQOX/dLzAyEDyfw3BI0AAgAJAAAEcgSNAAMACAA9sgUJChESObAFELAC0ACwAEVYsAIvG7ECHj5ZsABFWLAALxuxABA+WbIFAAIREjmxBwGwCitYIdgb9FkwMSEhATMDJwcDIQRy+5cBufZpEhPeAeMEjf7JS039bwAAAwBP//AEbwSdAAMAEgAgAHmyByEiERI5sAcQsAHQsAcQsBbQALAARViwDy8bsQ8ePlmwAEVYsAcvG7EHED5ZsgMPBxESOXywAy8YtGADcAMCXbQwA0ADAl2yAAMBcbEAAbAKK1gh2Bv0WbAPELEWAbAKK1gh2Bv0WbAHELEdAbAKK1gh2Bv0WTAxASE1IQUQACMiABE1NBI2MzIAESc0JiMiBhUVFBYzMjY1Azj+WgGmATf+3+3s/tqF8JvwASDyloiGmJmHiJQB38N2/vj+zAE1AQwurAEHi/7H/vUIt8DAtzWyx8O2AAEACQAABHIEjQAIADiyBwkKERI5ALAARViwAi8bsQIePlmwAEVYsAAvG7EAED5ZsABFWLAELxuxBBA+WbIHAgAREjkwMSEhATMBIQEnBwEK/v8BufYBuv7//t4SEwSN+3MDVktNAAMAQgAAA1UEjQADAAcACwBhsgQMDRESObAEELAA0LAEELAI0ACwAEVYsAovG7EKHj5ZsABFWLAALxuxABA+WbECAbAKK1gh2Bv0WbIHCgAREjmwBy+xBAGwCitYIdgb9FmwChCxCAGwCitYIdgb9FkwMSEhNSEDITUhEyE1IQNV/O0DE0n9fgKCSfztAxPDATjEAQrEAAEAdgAABGIEjQAHAECyAQgJERI5ALAARViwBi8bsQYePlmwAEVYsAQvG7EEED5ZsABFWLABLxuxARA+WbAGELECAbAKK1gh2Bv0WTAxISMRIREjESEEYvT9+/MD7APJ/DcEjQABAEQAAAPmBI0ADABNsgANDhESOQCwAEVYsAgvG7EIHj5ZsABFWLADLxuxAxA+WbEBAbAKK1gh2Bv0WbIFAQMREjmwCBCxCgGwCitYIdgb9FmyBwoIERI5MDEBASEVITUBATUhFSEBApD+5gJw/F4BP/7BA3z9ugEWAkX+f8SYAbcBppjE/o8AAwBQAAAFTQSNABEAFgAcAHGyCB0eERI5sAgQsBTQsAgQsBrQALAARViwEC8bsRAePlmwAEVYsAgvG7EIED5Zsg8QCBESObAPL7AA0LIJCBAREjmwCS+wBtCwCRCxFAGwCitYIdgb9FmwDxCxFQGwCitYIdgb9FmwGtCwFBCwG9AwMQEWBBUUBAcVIzUmJDU0JDc1MwECBREEBTQmJxEkA0nwART+6e3z8P7qARfv8/35BAEY/uwDGZCCARIEFQ/2ytD6D21sD/nQzfcNeP23/v0VAioV+4WBCv3WFQAAAQBQAAAFAwSNABgATLIAGRoREjkAsABFWLASLxuxEh4+WbAARViwDC8bsQwQPlmyFgwSERI5sBYvsADQsBIQsBfQsATQsBYQsQ0BsAorWCHYG/RZsArQMDEBNjY1ETMRBgcGBxEjESYCAxEzERQWFxEzAyN/bvMBaH368+P7AvNwffMB3RjCpwEv/s3jk68d/ugBFxYBKgEAATb+0ajAGAKvAAABAF8AAASEBJ0AIwBesgckJRESOQCwAEVYsBkvG7EZHj5ZsABFWLAPLxuxDxA+WbAARViwIi8bsSIQPlmwDxCxEQGwCitYIdgb9FmwDtCwANCwGRCxBwGwCitYIdgb9FmwERCwINCwIdAwMSU2NjU1NCYjIgYVFRQWFxUhNTMmETU0NjYzMgAVFRQGBzMVIQKteGyUjYqUdnT+MLC9g/Kc6gEqY1m2/i/IIsmwK56sqaQosccjyMSbAScWkeyE/uPtGY3fSsQAAAEAJP/sBVIEjQAZAG6yFhobERI5ALAARViwAi8bsQIePlmwAEVYsA4vG7EOED5ZsABFWLAYLxuxGBA+WbACELEAAbAKK1gh2Bv0WbAE0LAF0LIIAg4REjmwCC+wDhCxDwewCitYIdgb9FmwCBCxFQGwCitYIdgb9FkwMQEhNSEVIRU2MzIWFRQGIzUyNjU0JiMiBxEjAX7+pgOt/qCKjdrw8OtzdnR1gYXzA8nExO4n1Ma8wL1UaXJnJv3nAAABAE//8ARDBJ0AHQCSsgMeHxESOQCwAEVYsAsvG7ELHj5ZsABFWLADLxuxAxA+WbIPCwMREjmwCxCxEgGwCitYIdgb9FmyFQsDERI5sBUvsv8VAXGyDxUBcrI/FQFxss8VAXG0bxV/FQJxtK8VvxUCXbJfFQFyso8VAXKxFgGwCitYIdgb9FmwAxCxGgGwCitYIdgb9FmyHQMLERI5MDEBBgQjIgARNTQ2NjMyBBcjJiYjIgMhFSEWFjMyNjcEQhH+99ns/ux+7JzWAQQU8wx9cvsWAYD+gAp+g3h8DQGEv9UBLAELRKn/itrCcGn+z8SUn2JwAAACACQAAAcVBI0AFwAgAHqyBCEiERI5sAQQsBjQALAARViwEi8bsRIePlmwAEVYsAMvG7EDED5ZsABFWLALLxuxCxA+WbASELEFAbAKK1gh2Bv0WbALELEOAbAKK1gh2Bv0WbIUEgMREjmwFC+xGAGwCitYIdgb9FmwAxCxGQGwCitYIdgb9FkwMQEUBgchESEDBgIGIyM3NzY2NxMhETMyFiURMzI2NTQmIwcV+c/+Ff6kDgtYrJE0ASZgTgwVAzvs2vr9QPFndXZmAX+r0gIDyf6c7/7/dc0CB5/tAiv+bNAM/o5rU1FjAAACAHYAAAcYBI0AEwAcAMSyAR0eERI5sAEQsBTQALAARViwEy8bsRMePlmwAEVYsAIvG7ECHj5ZsABFWLAQLxuxEBA+WbAARViwDS8bsQ0QPlmyABATERI5sAAvtK8AvwACXbI/AAFxss8AAXGyPwABcrJfAAFysv8AAXGyDwABcrRvAH8AAnG03wDvAAJdtB8ALwACXbKfAAFysgQNAhESObAEL7AAELEPAbAKK1gh2Bv0WbAEELEUAbAKK1gh2Bv0WbANELEVAbAKK1gh2Bv0WTAxASERMxEzMhYWFRQGIyERIREjETMBETMyNjU0JiMBaQH98/KM0m//0v4f/gPz8wLw8Wd1dmYCngHv/mxfq3Cv0AHb/iUEjf2o/o5rU1FjAAEAJAAABVIEjQAVAFmyEhYXERI5ALAARViwAy8bsQMePlmwAEVYsBQvG7EUED5ZsABFWLANLxuxDRA+WbADELEEAbAKK1gh2Bv0WbAA0LIIFAMREjmwCC+xEQGwCitYIdgb9FkwMQEhNSEVIRU2MzIWFxEjETQmIyIHESMBfv6mA63+oIaO3usE83R0gYXzA8nExO0mz8v+mAFafGkm/ecAAAEAdv6fBGEEjQALAFCyAwwNERI5ALACL7AARViwBi8bsQYePlmwAEVYsAovG7EKHj5ZsABFWLAALxuxABA+WbAARViwBC8bsQQQPlmxCAGwCitYIdgb9FmwCdAwMSEhESMRIREzESERMwRh/orz/n7zAgXz/p8BYQSN/DYDygAAAgB2AAAEKASNAAsAFABhsggVFhESObAIELAM0ACwAEVYsAovG7EKHj5ZsABFWLAILxuxCBA+WbAKELEAAbAKK1gh2Bv0WbIDCggREjmwAy+wCBCxDAGwCitYIdgb9FmwAxCxEgGwCitYIdgb9FkwMQEhFTMWFhAGIyERIQEyNjU0JicjEQOy/bf8z/T42f4fAzz+qGhzcGb2A8vgA8T+qMwEjfw2Y1RPXQH+nAAAAgAn/q8FFQSNAA8AFQBdshMWFxESObATELAF0ACwDS+wAEVYsAUvG7EFHj5ZsABFWLALLxuxCxA+WbEAAbAKK1gh2Bv0WbAH0LAI0LANELAK0LAIELAQ0LAR0LAFELESAbAKK1gh2Bv0WTAxNz4CNxMhETMRIxEhESMTISERIQcCgkpCIwUMAz2W8vz38wEBdAHw/qEHDcNRhrR+AcH8Nv3sAVH+rwIUAwb8/q4AAQAaAAAGHwSNABUAn7IBFhcREjkAsABFWLARLxuxER4+WbAARViwDi8bsQ4ePlmwAEVYsAovG7EKHj5ZsABFWLAGLxuxBhA+WbAARViwAy8bsQMQPlmwAEVYsBUvG7EVED5ZsgwDDhESObAML7I/DAFxsl8MAXKyzwwBcbSvDL8MAl20jwyfDAJysA/QsQEBsAorWCHYG/RZsATQsggPBBESObITAQ8REjkwMQEjESMRIwMhAQEhEzMRMxEzEyEBASED9V/zYPz+0wFc/sQBHvdU81T3AR7+wgFe/tMB1f4rAdX+KwJUAjn+IAHg/iAB4P3Q/aMAAQBC//AD5wSdACcAjbImKCkREjkAsABFWLAKLxuxCh4+WbAARViwFi8bsRYQPlmwChCxAwGwCitYIdgb9FmyBgoWERI5siYKFhESObAmL7LPJgFxsj8mAXG0rya/JgJdsv8mAXGyDyYBcrJfJgFysSMBsAorWCHYG/RZshAjJhESObIcFgoREjmwFhCxHgGwCitYIdgb9FkwMQE0JiMiBhUjNDYzMhYVFAYHFhYVFAQjIiYnJjUzFjMyNjU0JyM1MzYC4nBrW2bz88PY9G5db27+/txdrz988wvKd3TglJrHA0NGT0Y8lLOnlluKJySRW5+1LS9bn5NXSKYDsAQAAAEAdgAABG4EjQAJAEyyAAoLERI5ALAARViwAC8bsQAePlmwAEVYsAgvG7EIHj5ZsABFWLAFLxuxBRA+WbAARViwAy8bsQMQPlmyBAMAERI5sgkFCBESOTAxATMRIxEBIxEzEQN78/P97vPzBI37cwMj/N0EjfzgAAEAdgAABEAEjQAMAHiyAA0OERI5ALAARViwCC8bsQgePlmwAEVYsAUvG7EFHj5ZsABFWLACLxuxAhA+WbAARViwDC8bsQwQPlmyBgIFERI5sAYvsj8GAXGyXwYBcrLPBgFxtK8GvwYCXbSPBp8GAnKxAQGwCitYIdgb9FmyCgEGERI5MDEBIxEjETMRMwEhAQEhAdNq8/NjATgBHf5yAa3+0QHV/isEjf4gAeD9xf2uAAABACQAAARVBI0AEABPsgQREhESOQCwAEVYsAAvG7EAHj5ZsABFWLABLxuxARA+WbAARViwCS8bsQkQPlmwABCxAwGwCitYIdgb9FmwCRCxDAGwCitYIdgb9FkwMQERIxEhAwYCBgcjNzc2NjcTBFXz/qQPDFeqjDoBJ2JKDBYEjftzA8n+n+3+/ngBzQQLoOYCKwAAAQAf/+wEOQSNAA8ARLIAEBEREjkAsABFWLAPLxuxDx4+WbAARViwAi8bsQIePlmwAEVYsAgvG7EIED5ZsgEIDxESObELAbAKK1gh2Bv0WTAxARcTIQEOAiMnNxcyNwEhAikT8wEK/nA4Wn5aZgFXYDP+WwEOAks3Ann8fn5pOAXABGEDfwABAHb+rwUkBI0ACwBDsgkMDRESOQCwAy+wAEVYsAcvG7EHHj5ZsABFWLAKLxuxCh4+WbAARViwBS8bsQUQPlmxCAGwCitYIdgb9FmwANAwMSUzAyMRIREzESERMwRiwhTd/EPzAgX0w/3sAVEEjfw2A8oAAAEAQQAABBYEjQARAEeyBBITERI5ALAARViwCS8bsQkePlmwAEVYsBAvG7EQHj5ZsABFWLABLxuxARA+WbINAQkREjmwDS+xBAGwCitYIdgb9FkwMSEjEQYjIiYnETMRFBYzMjcRMwQW84aB6vAB8295goXzAaom0tEBZv6ed2wmAh8AAAEAdgAABg4EjQALAEKyBwwNERI5ALAARViwAy8bsQMePlmwAEVYsAEvG7EBED5ZsQQBsAorWCHYG/RZsAMQsAbQsAQQsAjQsAYQsArQMDEhIREzESERMxEhETMGDvpo8wFf8wFg8wSN/DYDyvw2A8oAAAEAdv6vBtEEjQAPAEKyCxARERI5ALADL7AARViwBy8bsQcePlmwAEVYsAQvG7EEED5ZsQABsAorWCHYG/RZsA3QsAnQsAcQsArQsA7QMDElMwMjESERMxEhETMRIREzBg/CFN36lvMBX/MBYPTD/ewBUQSN/DYDyvw2A8oAAAIACgAABRsEjQAMABUAYbIIFhcREjmwCBCwFNAAsABFWLAHLxuxBx4+WbAARViwAy8bsQMQPlmwBxCxBQGwCitYIdgb9FmyCgcDERI5sAovsAMQsQ0BsAorWCHYG/RZsAoQsRMBsAorWCHYG/RZMDEBFAYHIREhNSERMzIWATI2NTQmJyMRBRv5z/4V/qICUuvb+f4yZnVxYvkBf6vSAgPJxP5s0P6aa1NPYwL+jgD//wB2AAAFqQSNACYCCAAAAAcB4wQyAAAAAgB2AAAEKASNAAsAFABPsgMVFhESObADELAM0ACwAEVYsAYvG7EGHj5ZsABFWLAELxuxBBA+WbIHBAYREjmwBy+xEwGwCitYIdgb9FmwBBCxFAGwCitYIdgb9FkwMQEUBiMhETMRMzIWFgEyNjU0JicjEQQo/9L+H/PyjNJv/jJmdXFi+QF/r9AEjf5sX6v+1GtTT2MC/o4AAAEAPP/wBDAEnQAdAIqyAx4fERI5ALAARViwEi8bsRIePlmwAEVYsBovG7EaED5ZsgAaEhESObEDAbAKK1gh2Bv0WbIJEhoREjmwCS+yzwkBcbI/CQFxtG8JfwkCcbSvCb8JAl2y/wkBcbIPCQFysl8JAXKxBgGwCitYIdgb9FmwEhCxCwGwCitYIdgb9FmyDhIaERI5MDEBFhYzMjY3ITUhAiMiBgcjNiQzMgAXFxQGBiMiJCcBLw18eIKACv5/AYAW+3J9DPMUAQTW4gEXDAF76pvc/vgPAYRwYp+UxAExaXDC2v7o8HWp/4jaugACAHb/8AZBBJ0AEwAhALKyBCIjERI5sAQQsBnQALAARViwEC8bsRAePlmwAEVYsAsvG7ELHj5ZsABFWLADLxuxAxA+WbAARViwCC8bsQgQPlmyDQgLERI5sA0vtK8Nvw0CXbRvDX8NAnGy/w0BcbIPDQFytI8Nnw0CcrJfDQFyss8NAXGyPw0BcbQfDS8NAl2yzw0BcrEGAbAKK1gh2Bv0WbAQELEXAbAKK1gh2Bv0WbADELEeAbAKK1gh2Bv0WTAxARAAIyIAJyMRIxEzETM2ADMyABEnNCYjIgYVFRQWMzI2NQZB/t/t3v7iE7zy8rwUAR3c8AEg8paIhpiZh4iUAiz++P7MARDi/h4Ejf4Y6QEP/sf+9Qi3wMC3NbLHw7YAAAIAQwAABBIEjQAMABUAXLIGFhcREjmwBhCwENAAsABFWLAHLxuxBx4+WbAARViwCS8bsQkQPlmyEQkHERI5sBEvsQoBsAorWCHYG/RZsgEKERESObAJELAM0LAHELESAbAKK1gh2Bv0WTAxMwEmNTQ2MyERIxEjAxMUFjMzESMiBkMBFtbw0wHM8/HmLmFr3d1hawIKVtGjuftzAbz+RAMiSlkBSlcAAAEACgAAA/8EjQANAFKyAQ4PERI5ALAARViwCC8bsQgePlmwAEVYsAIvG7ECED5ZsgcCCBESObAHL7EEB7AKK1gh2Bv0WbAB0LAIELELAbAKK1gh2Bv0WbAHELAM0DAxASMRIxEjNTMRIRUhETMCp9bz1NQDIf3S1gHm/hoB5qoB/cT+xwAAAQAa/q8GbQSNABkAprIIGhsREjkAsAMvsABFWLARLxuxER4+WbAARViwBS8bsQUQPlmwAEVYsAkvG7EJED5ZsABFWLANLxuxDRA+WbIXCREREjmwFy+yPxcBcbJfFwFyss8XAXG0rxe/FwJdtI8XnxcCcrEHAbAKK1gh2Bv0WbIABxcREjmwBRCxAQGwCitYIdgb9FmwBxCwC9CyDxcHERI5sBcQsBLQsBEQsBTQsBjQMDEBEzMRIxEjAyMRIxEjAyEBASETMxEzETMTIQTB7r7Qq/1f82D8/tMBXP7EAR73VPNU9wEeAl3+Zf3tAVEB1f4rAdX+KwJUAjn+IAHg/iAB4AABAHb+rwR8BI0AEACKsgAREhESOQCwBC+wAEVYsAwvG7EMHj5ZsABFWLAPLxuxDx4+WbAARViwCS8bsQkQPlmwAEVYsAYvG7EGED5Zsg0JDBESObANL7I/DQFxsl8NAXKyzw0BcbSvDb8NAl20jw2fDQJysQgBsAorWCHYG/RZsgAIDRESObAGELEBAbAKK1gh2Bv0WTAxAQEzESMRIwEjESMRMxEzASECkwEhyNCb/sJq8/NjATgBHQJS/nD97QFRAdX+KwSN/iAB4AABAHYAAAT+BI0AFACBsgUVFhESOQCwAEVYsBQvG7EUHj5ZsABFWLAGLxuxBh4+WbAARViwES8bsREQPlmwAEVYsAovG7EKED5ZsgARFBESObAAL7I/AAFxsl8AAXKyzwABcbSvAL8AAl20jwCfAAJysATQsAAQsRABsAorWCHYG/RZsAzQsggMABESOTAxATM1MxUzASEBASEBIxUjNSMRIxEzAWlHozcBOAEc/nIBrv7R/sI+o0fz8wKt3t4B4P3E/a8B1cvL/isEjQABACQAAAVOBI0ADgCHsgkPEBESOQCwAEVYsAcvG7EHHj5ZsABFWLAKLxuxCh4+WbAARViwAi8bsQIQPlmwAEVYsA4vG7EOED5ZsggCBxESObAIL7I/CAFxsl8IAXKyzwgBcbSvCL8IAl20jwifCAJysQEBsAorWCHYG/RZsAcQsQQBsAorWCHYG/RZsgwBCBESOTAxASMRIxEhNSERMwEhAQEhAuFq8/6gAlNjATgBHf5yAa3+0QHV/isDysP+IAHg/cT9rwACAE//6wWYBKUAIwAuAJCyFS8wERI5sBUQsCTQALAARViwGy8bsRsePlmwAEVYsAsvG7ELHj5ZsABFWLAELxuxBBA+WbAARViwAC8bsQAQPlmyAgQbERI5sAIvsAsQsQwBsAorWCHYG/RZsAQQsRMBsAorWCHYG/RZsAAQsSMBsAorWCHYG/RZsAIQsCbQsBsQsSwBsAorWCHYG/RZMDEFIicGIyAAAzU0ADMVIgYVFRQWMzM3JgM1NBIzMhIXFRAHFjMBEBc2NzU0JiMiEQWY466Rqf7a/qwEAQjbcX/LwBsbwALcv8bdAaNfXP2UvqIBU1uzEDk+ATwBGDr+AS7MtLEmy80CqgEeLOoBDf787Ej+/60LAdL+9G948zWgkP7S//8ABQAABDYEjQAmAdMAAAAHAiYAO/7VAAEAFf6vBIsEjQAPAFuyChARERI5ALAHL7AARViwAS8bsQEePlmwAEVYsA8vG7EPHj5ZsABFWLALLxuxCxA+WbAARViwCS8bsQkQPlmyAA8LERI5sQQBsAorWCHYG/RZsgoLDxESOTAxARMhAQEzESMRIwMDIQEBIQIn8gEc/okBCcTPkv/6/uQBgf6IARoC+gGT/b7+d/3tAVEBmf5nAksCQgAAAQAk/q8GLgSNAA8AXrIJEBEREjkAsAIvsABFWLAILxuxCB4+WbAARViwDi8bsQ4ePlmwAEVYsAQvG7EEED5ZsQABsAorWCHYG/RZsAgQsQYBsAorWCHYG/RZsArQsAvQsAAQsAzQsA3QMDElMwMjESERITUhFSERIREzBWrEFN78RP6kA6L+rAIG8sP97AFRA8nExPz6A8oAAAEAQQAABBYEjQAXAFCyBBgZERI5ALAARViwDC8bsQwePlmwAEVYsBYvG7EWHj5ZsABFWLABLxuxARA+WbIQAQwREjmwEC+xBwGwCitYIdgb9FmwBNCwEBCwE9AwMSEjEQYHFSM1JiYnETMRFBYXNTMVNjcRMwQW80xWo8zPAvNUVqNKWPMBqhYKzMgN0b8Bav6fa2kM8/IJGAIfAAEAdgAABEsEjQARAEeyBBITERI5ALAARViwAS8bsQEePlmwAEVYsBAvG7EQED5ZsABFWLAJLxuxCRA+WbIEEAEREjmwBC+xDQGwCitYIdgb9FkwMRMzETYzMhYVESMRNCYjIgcRI3bzhoDt7/N1dIGF8wSN/lYm1tH+ngFhfGkm/eAAAAIACv/wBagEowAbACMAZ7INJCUREjmwDRCwHdAAsABFWLAOLxuxDh4+WbAARViwAC8bsQAQPlmyIA4AERI5sCAvsRIBsAorWCHYG/RZsAPQsCAQsArQsAAQsRUBsAorWCHYG/RZsA4QsRwBsAorWCHYG/RZMDEFIAAnJiY1MxQWFz4CMyAAERUhEiEyNzcXBgYDIgYHITU0JgPJ/vr+wAyuv8FUWAmP8ZEBAAEX/MASAU+Gcy9BO8WhgKAIAkyVEAER6gvdu112DJLkfv7l/veV/tArErohLAPupYwWhpUAAgBP//AEgQSjABYAHgBhsggfIBESObAIELAX0ACwAEVYsAAvG7EAHj5ZsABFWLAILxuxCBA+WbINAAgREjmwDS+wABCxEAGwCitYIdgb9FmwCBCxFwGwCitYIdgb9FmwDRCxGgGwCitYIdgb9FkwMQEgABcVFAYGIyAAETUhJiYjIgcHJzY2EzI2NyEVFBYCOQELATsCjPmW/v7+6wM/B7OmhnYtQUDJmIGeCv20lASj/tz5epv5iAEcAQiVlposEboiK/wSo44WhpUAAQBC/+wD6ASNABkAbLISGhsREjkAsABFWLACLxuxAh4+WbAARViwCy8bsQsQPlmwAhCxAAGwCitYIdgb9FmyBAIAERI5shkLAhESObAZL7AF0LIPCwIREjmwCxCxEgGwCitYIdgb9FmwGRCxGAewCitYIdgb9FkwMQEhNSEXARYWFRQEIyImNTMWFjMyNjU0IyM1Ao393gNSAf7GosL/AN/Q9/MEcWVzc/F9A8nEm/7AFL+LqMC5oUlQWlOwuwAAAwBP//AEbwSdAA4AFQAcAIGyAx0eERI5sAMQsA/QsAMQsBbQALAARViwCy8bsQsePlmwAEVYsAMvG7EDED5ZsAsQsQ8BsAorWCHYG/RZshMLAxESOXywEy8YtGATcBMCXbQwE0ATAl2y8BMBXbIAEwFxsAMQsRYBsAorWCHYG/RZsBMQsRkBsAorWCHYG/RZMDEBEAAjIgARNTQSNjMyABEBIgYHISYmAzI2NyEWFgRv/t/t7P7ahfCb8AEg/fB5lA4CNg6TeHmRDv3MD5UCLP74/swBNQEMLqwBB4v+x/71AX+dlZWd/Nudk5OdAAEAOAAABBoEnQAnALKyJSgpERI5ALAARViwHS8bsR0ePlmwAEVYsAwvG7EMED5ZsgYdDBESObAGL7IPBgFdsAHQsAEvss8BAV1ACR8BLwE/AU8BBF2yAAEBXbECArAKK1gh2Bv0WbAGELEHArAKK1gh2Bv0WbAMELEKAbAKK1gh2Bv0WbAO0LAP0LAHELAR0LAGELAT0LACELAW0LABELAY0LAdELEkAbAKK1gh2Bv0WbIhJAEREjmyDCEBXTAxASEVIRcVIRUhBgchByE1MzY3IzUzNScjNTMnJjYzMhYVIzQmIyIGFwHEAYP+ggMBe/5zEiYCmAH8ZQo0EpahA56ZAQbYv8TX81RTTVcFArqSQhaTRTXDww5skw5KkifO7tC2Wmd+eQAAAQBG//ADsASeACIApLIKIyQREjkAsABFWLAWLxuxFh4+WbAARViwCS8bsQkQPlmyIhYJERI5sCIvsg8iAV20ECIgIgJdsQACsAorWCHYG/RZsAkQsQQBsAorWCHYG/RZsAAQsAzQsCIQsA7QsCIQsBPQsBMvss8TAV22HxMvEz8TA12yABMBXbEQArAKK1gh2Bv0WbAWELEbAbAKK1gh2Bv0WbATELAd0LAQELAf0DAxASEWFjMyNxcGIyIkJyM1MzUjNTM2NjMyFwcmIyIHIRUhFSEDTv6DEXtvUHkbdm7U/v8al5KSmBr/02x6Flt11iIBfP59AYMBhGpoHL8f0MSSXJPD1iC/HNaTXAAABAB2AAAHxwSeAAMADwAdACcArbIeKCkREjmwHhCwAdCwHhCwBNCwHhCwENAAsABFWLAmLxuxJh4+WbAARViwJC8bsSQePlmwAEVYsAYvG7EGHj5ZsABFWLAhLxuxIRA+WbAARViwHy8bsR8QPlmwBhCwDdCwDS+wAtCwAi+2AAIQAiACA12xAQKwCitYIdgb9FmwDRCxEwKwCitYIdgb9FmwBhCxGgKwCitYIdgb9FmyICQhERI5siUfJhESOTAxJSE1IQE0NiAWFRUUBiAmNRcUFjMyNjc1NCYjIgYVASMBESMRMwERMweI/cUCO/2KvwE2wL7+ysGvWlNQWAJdT05d/qby/fTz8wIM8siVAfKWubicSJa4uJsFV2ViVFNXZGNb/LQDG/zlBI385AMcAAIAKAAABKoEjQAVAB4Aj7INHyAREjmwDRCwF9AAsABFWLAMLxuxDB4+WbAARViwAy8bsQMQPlmyBgMMERI5sAYvsQUBsAorWCHYG/RZsAHQsAYQsArQsAovtg8KHwovCgNdto8KnwqvCgNdtB8KLwoCcbEJAbAKK1gh2Bv0WbAT0LAGELAU0LAKELAW0LAMELEeAbAKK1gh2Bv0WTAxJSEVIzUjNTM1IzUzESEyFhAGByEVIQEzMjY1NCYjIwL2/vXz0NDQ0AHr0fbtyP72AQv+9fhhc3Ve+ZmZmbZNtwI60/60zQVNAQRnVVZlAAABADf/9QKpAyAAJACCsh4lJhESOQCwAEVYsA0vG7ENGj5ZsABFWLAXLxuxFxA+WbIAFw0REjl8sAAvGLRQAGAAAnG2gACQAKAAA12wDRCxBgKwCitYIdgb9FmyCgAGERI5sAAQsSQCsAorWCHYG/RZshIkABESObAXELEeArAKK1gh2Bv0WbIbJB4REjkwMQEzMjU0JiMiBhUjNDYzMhYVFAcWFRQGIyImNTMUFjMyNjU0JyMBDFGENj4wQbqlgo+jh5Wxj4erukU8Pz2GXAHSYSM1JyNjfHlpdzMpjmp+f3EmNTcqZQEAAgA1AAACvgMVAAoADgBKALAARViwCS8bsQkaPlmwAEVYsAQvG7EEED5ZsgEJBBESObABL7ECArAKK1gh2Bv0WbAG0LABELAL0LIICwYREjmyDQkEERI5MDEBMxUjFSM1IScBMwEzNQcCX19fu/6aCQFtvf6Lug4BOpejo3kB+f4l8hYAAQBP//UCrgMVABoAbbINGxwREjkAsABFWLACLxuxAho+WbAARViwDS8bsQ0QPlmwAhCxAwKwCitYIdgb9FmyBwINERI5sAcvsRgCsAorWCHYG/RZsgUYBxESObANELETArAKK1gh2Bv0WbIRExgREjmyGhgTERI5MDETEyEVIQc2MzIWFRQGIyImJzMWMzI1NCYjIgdiNAHs/qwUPkeDjKOMga0CuQVydUNCQzUBfwGWlpQbhnp4mYRjUn04RCgAAgBN//UCuQMiABMAHgBeshQfIBESObAUELAM0ACwAEVYsAAvG7EAGj5ZsABFWLAMLxuxDBA+WbAAELEBArAKK1gh2Bv0WbIGDAAREjmwBi+xFAKwCitYIdgb9FmwDBCxGgKwCitYIdgb9FkwMQEVIgYHNjMyFhUUBiMiJjU1NDYzAyIGBxUUMzI2NTQCMpGJDUdrdYeohpOr8N6WLUIPfzVEAyKZX2JFjnp3maebMdLo/lckFySRRjZ0AAABADYAAAKuAxUABgAzALAARViwBS8bsQUaPlmwAEVYsAIvG7ECED5ZsAUQsQQCsAorWCHYG/RZsgAEBRESOTAxAQEjASE1IQKu/q3EAVP+TAJ4Aqz9VAJ/lgADAEv/9QKqAyAAEwAcACQAmbIHJSYREjmwBxCwFNCwBxCwItAAsABFWLARLxuxERo+WbAARViwBy8bsQcQPlmyIgcRERI5fLAiLxi2gCKQIqAiA120UCJgIgJxtAAiECICcbRAIlAiAl200CLgIgJxsRkCsAorWCHYG/RZsgIiGRESObIMGSIREjmwBxCxFAKwCitYIdgb9FmwERCxHwKwCitYIdgb9FkwMQEUBxYVFAYjIiY1NDcmNTQ2MzIWATI2NCYiBhQWEzQiFRQWMjYCl3GEoY6MpIRxm4GCm/7kNUBBakBAl8QzYDECQXQ3PYBqenlrgD03dGl2dv3gM1owMFozAatWVicwMAAAAgBG//cCowMgABMAHwBjshQgIRESObAUELAI0ACwAEVYsAgvG7EIGj5ZsABFWLAQLxuxEBA+WbICEAgREjl8sAIvGLAQELERArAKK1gh2Bv0WbACELEUArAKK1gh2Bv0WbAIELEaArAKK1gh2Bv0WTAxAQYjIiY1NDYzMhYXFRQGByM1MjYnMjc1NCYjIgYVFBYB50JafoeqhIuiAtzgE495Y04jQjQzQTwBNjmKfXikppc719kBk1KsNEVIQU45N0QAAAEAkAKHAy0DMQADABIAsAIvsQEHsAorWCHYG/RZMDEBITUhAy39YwKdAoeqAAADAJYESAKiBpUAAwAPABsAUACwDS+wGdCwGS+xBwmwCitYIdgb9FmwAtCwAi+wANCwAC9ADw8AHwAvAD8ATwBfAG8AB12wAhCwA9AZsAMvGLANELETCbAKK1gh2Bv0WTAxATMHIwc0NjMyFhUUBiMiJjcUFjMyNjU0JiMiBgG85vWVgm5OTGxpT1FrYzQlJDAwJCU0BpXC3k5kZU1KY2JLJTExJSczMwABAHYAAAO1BI0ACwBRALAARViwBi8bsQYePlmwAEVYsAQvG7EEED5ZsgsGBBESObALL7EAAbAKK1gh2Bv0WbAEELECAbAKK1gh2Bv0WbAGELEIAbAKK1gh2Bv0WTAxASERIRUhESEVIREhA1/+CgJM/MEDPP23AfYB+P7KwgSNxP7yAAADAAr+SgQbBE4AKQA2AEMAoLIIREUREjmwCBCwMNCwCBCwOtAAsABFWLAmLxuxJhw+WbAARViwFi8bsRYSPlmwJhCwKNCwKC+xAAOwCitYIdgb9FmyCBYmERI5sAgvsg8WCBESObAPL7E1AbAKK1gh2Bv0WbIbNQ8REjmyHwgmERI5sBYQsTABsAorWCHYG/RZsAgQsToBsAorWCHYG/RZsCYQsUEBsAorWCHYG/RZMDEBIxYVFRQGBiMiJwYVFBczFhYVFAYGIyIkNTQ3JjU0NyYmNTU0NjMyFyEBBgYVFBYzMjY1NCclAxQWMzI2NTU0JiIGFQQbijpzzoBRRSVzwsPKj/qa2f71tjJ1WmT8x1VLAXH9MCQxiHKGrJP+6kB6WVh3dbh1A6BVaRZkqV8SIy9KAwGajlimYpt5pVkySHdRMZ5fFqLKFPvlE0gwQk1eQGsJAgKzS2ZnThJKZmZNAAACAFb/6wRfBE4AEAAdAHCyGx4fERI5sBsQsAnQALAARViwCS8bsQkcPlmwAEVYsAwvG7EMHD5ZsABFWLACLxuxAhA+WbAARViwEC8bsRAQPlmyAAkCERI5sgsJAhESObACELEUAbAKK1gh2Bv0WbAJELEbAbAKK1gh2Bv0WTAxJQYjIgI1NRASMzIXNzMDEyMBFBYzMjY3NSYmIyIGA2Nu8sfm6MfpcRzdbHPd/cd8dGB8FxF9Y3N/xNkBIPQPAQoBNtfD/eL95AH5oKyrpi+lucUAAAIAmwAABPIFsAAWAB4AY7IYHyAREjmwGBCwBNAAsABFWLADLxuxAyA+WbAARViwAS8bsQEQPlmwAEVYsA8vG7EPED5ZshcDARESObAXL7EAAbAKK1gh2Bv0WbIJABcREjmwAxCxHQGwCitYIdgb9FkwMQERIxEhMhYVFAcWExUUFxUhJic1NCYjJSEyNjU0ISEBl/wCKfX/9+UFR/78OwR7cP7TARSQgf74/uMCVv2qBbDZzeNlRf72c6k9GjG4eXSAynFt5gAAAQCbAAAFMAWwAAwAWQCwAEVYsAQvG7EEID5ZsABFWLAILxuxCCA+WbAARViwAi8bsQIQPlmwAEVYsAsvG7ELED5ZsgYCBBESObAGL7IfBgFxsQEBsAorWCHYG/RZsgoBBhESOTAxASMRIxEzETMBIQEBIQJDrPz8iwGsATb+DAIg/tACcP2QBbD9nAJk/Uf9CQABAIEAAAQ1BgAADABUALAARViwBC8bsQQiPlmwAEVYsAgvG7EIHD5ZsABFWLACLxuxAhA+WbAARViwCy8bsQsQPlmyBwgCERI5sAcvsQABsAorWCHYG/RZsgoABxESOTAxASMRIxEzETMBIQEBIQHib/LyaQEPARz+nwGP/uYB2f4nBgD8nAGe/hH9tQAAAQCbAAAFEgWwAAsATACwAEVYsAMvG7EDID5ZsABFWLAHLxuxByA+WbAARViwAS8bsQEQPlmwAEVYsAovG7EKED5ZsgADARESObIFAwEREjmyCQAFERI5MDEBESMRMxEzASEBASEBl/z8BgIZATj9pQJ//sgCmv1mBbD9fwKB/TX9GwAAAQCBAAAEIgYYAAoATACwAEVYsAMvG7EDIj5ZsABFWLAGLxuxBhw+WbAARViwAS8bsQEQPlmwAEVYsAkvG7EJED5ZsgAGARESObIFBgEREjmyCAAFERI5MDEBESMRMxEBIQEBIQFz8vIBWQEq/lAB3P7bAev+FQYY/IQBnv4M/boAAAIAdgAABCoEjQALABMASLITFBUREjmwExCwAtAAsABFWLABLxuxAR4+WbAARViwAC8bsQAQPlmwARCxDAGwCitYIdgb9FmwABCxDQGwCitYIdgb9FkwMTMRITIEFhcVFAYEIwMRMyATNRAldgF7pAEDkAKP/vmog4IBRwb+yQSNivufPaP+iwPJ/PkBXEMBYAgAAQBP//AEQwSdABsAULIDHB0REjkAsABFWLALLxuxCx4+WbAARViwAy8bsQMQPlmyDwsDERI5sAsQsRIBsAorWCHYG/RZsAMQsRgBsAorWCHYG/RZshsDCxESOTAxAQYEIyIAETU0NjYzMgQXIyYmIyARFRQWMzI2NwRCEf732ez+7H7snNYBBBTzDH1y/u2Gh3h8DQGEv9UBLAELRKn/itrCcGn+jki5tWJwAAMAdgAABAoEjQAOABYAHwCnsh4gIRESObAeELAC0LAeELAR0ACwAEVYsAEvG7EBHj5ZsABFWLAALxuxABA+WbIXAQAREjmwFy+0rxe/FwJdtG8XfxcCcbL/FwFxsg8XAXK0jxefFwJysl8XAXKyzxcBcbI/FwFxtB8XLxcCXbS/F88XAnKxDwGwCitYIdgb9FmyCA8XERI5sAAQsRABsAorWCHYG/RZsAEQsR4BsAorWCHYG/RZMDEzESEyFhUUBgcWFhUUBiMDETMyNjU0JyczNjY1NCYjI3YBr97rWVtgcOLd4uRmZLT61FtjZ2XGBI2lnE+DIxePY6OrAfv+x1VBngWqAkhFT0YAAgAJAAAElASNAAcACgBHALAARViwBC8bsQQePlmwAEVYsAIvG7ECED5ZsABFWLAGLxuxBhA+WbIJBAIREjmwCS+xAAGwCitYIdgb9FmyCgQCERI5MDElIQcjATMBIwEhAwM//h5f9QHX3wHV9v4GAVSq+fkEjftzAbIBugAAAQCUBGkBqQYrAAgAHbIICQoREjkAsABFWLAALxuxACI+WbAE0LAELzAxARcGBwcjNTQ2ASaDPwIB01UGK1NtfIaFWbYAAAIAdQTUAwAGfgANABEAXgCwAy+wBtCwBi9ACw8GHwYvBj8GTwYFXbADELEKBrAKK1gh2Bv0WbAGELAN0LANL7AGELAR0LARL7AO0LAOL0APDw4fDi8OPw5PDl8Obw4HXbARELAQ0BmwEC8YMDEBFAYjIiY1MxQWMzI2NSUzFyMDAK+WlbGxTElHTP6Ut3KABbFhfHpjNDw8NM3AAAL8nQS8/tYGjAATABcAdgCwAy+wBtCwBi9ADQ8GHwYvBj8GTwZfBgZdsAMQsAnQsAkvsAYQsQ0IsAorWCHYG/RZsAMQsRAIsAorWCHYG/RZsA0QsBPQsAYQsBbQfLAWLxhACQ8WHxYvFj8WBF2wFNCwFC+2PxRPFF8UA120DxQfFAJdMDEBFAYjIiYjIgYVJzQ2MzIWMzI2NSczByP+1l9GOIMpHypnX0YsjiodLIjDto0FgkxpRjIlHEttRjEl7NQAAgB6BOcEiwaQAAYACgBbALADL7AF0LAFL7AA0LAAL0AJDwAfAC8APwAEXbADELAC0BmwAi8YsgQDABESObAG0BmwBi8YsAMQsAnQsAkvsAfQsAcvtg8HHwcvBwNdsAkQsArQGbAKLxgwMQEzBSMnByMBMwMjAZ2hASPUn5/VAzPe2J0F4fqOjgGp/vUAAAL/TATaA1wGgwAGAAoAWwCwAy+wBNAZsAQvGLAA0BmwAC8YsAMQsAHQsAEvsAbQsAYvQAkPBh8GLwY/BgRdsgIDBhESObADELAI0LAIL7AH0BmwBy8YsAgQsArQsAovtg8KHwovCgNdMDEBIycHIyUzBSMDMwNc1Z+f1AEjof6HndfdBNqOjvpcAQsAAgB1BOcECgbLAAYAFQBhALABL7AD0LADL7AE0BmwBC8YsADQGbAALxiwAxCwBdCwBS9ACQ8FHwUvBT8FBF2yAgMFERI5sAEQsAfQsAcvsA3QsA0vsggHDRESObEOBrAKK1gh2Bv0WbIUCAcREjkwMQEjJwcjJTMXJzY2NTQjNzIWFRQGBwcDXMGzssEBFru5Bz84gQeJjEk4AQTnoqL6dH0FGB0+aVlLN0EHOwAAAgB1BOcDXAbRAAYAGgCPALABL7AD0LADL7AE0BmwBC8YsADQGbAALxiwAxCwBdCwBS9ACQ8FHwUvBT8FBF2yAgUDERI5sArQsAovQAk/Ck8KXwpvCgRdsA3QsA0vQA8PDR8NLw0/DU8NXw1vDQddsAoQsBDQsBAvsA0QsRQGsAorWCHYG/RZsAoQsRcGsAorWCHYG/RZsBQQsBrQMDEBIycHIyUzNxQGIyImIyIGFSc0NjMyFjMyNjUDXMGzssEBKpO6WT0xeyQbKVpZPCp/JhosBOeOju3fPl9CLBsYQGBBLRwAAQB2AAADlwXEAAcAM7IDCAkREjkAsABFWLAGLxuxBh4+WbAARViwBS8bsQUQPlmwBhCxAgGwCitYIdgb9FkwMQEzESERIxEhAqTz/dLzAi4FxP4F/DcEjQAAAgB1BNMDAAZ+AA0AEQBeALADL7AG0LAGL0ALDwYfBi8GPwZPBgVdsAMQsQoGsAorWCHYG/RZsAYQsA3QsA0vsAYQsBDQsBAvsA7QsA4vQA8PDh8OLw4/Dk8OXw5vDgddsBAQsBHQGbARLxgwMQEUBiMiJjUzFBYzMjY1JzMHIwMAr5aVsbFMSUdMZbapgAWwYXx6YzQ8PDTOwAAAAgB1BNUC9gcIAA0AHABbALADL7AH0LAHL0ALDwcfBy8HPwdPBwVdsAMQsQoGsAorWCHYG/RZsAcQsA3QsA0vsAcQsA7QsA4vsBTQsBQvsg8OFBESObEVDLAKK1gh2Bv0WbIbDg8REjkwMQEUBiMiJjUzFBYzMjY1Jyc2NjU0IzcyFhUUBgcHAvavkZKvrVBERU3fCEg/kgeen05EAQWwYnl5YjQ5OjMZdgIXGjZgUEQvOgg6AP//AEsCjQKqBbgDBwHHAAACmAATALAARViwCi8bsQogPlmwENAwMQD//wA1ApgCvgWtAwcCIAAAApgAEwCwAEVYsAkvG7EJID5ZsA3QMDEA//8ATwKNAq4FrQMHAiEAAAKYABAAsABFWLABLxuxASA+WTAx//8ATQKNArkFugMHAiIAAAKYABMAsABFWLAALxuxACA+WbAU0DAxAP//ADYCmAKuBa0DBwIjAAACmAAQALAARViwBS8bsQUgPlkwMf//AEsCjQKqBbgDBwIkAAACmAAZALAARViwES8bsREgPlmwGdCwERCwH9AwMQD//wBGAo8CowW4AwcCJQAAApgAEwCwAEVYsAgvG7EIID5ZsBrQMDEAAAEAa//rBSYFxQAdAEKyDB4fERI5ALAARViwDC8bsQwgPlmwAEVYsAMvG7EDED5ZsAwQsRMBsAorWCHYG/RZsAMQsRoBsAorWCHYG/RZMDEBBgAjIiQCJzU0EiQzMgAXIyYmIyICFRUUEjMyNjcFJBf+0vm2/tygAZ4BILf7ATQX/RajkKzM0qyRmxYB2un++rQBRdI81QFKtP7z6ZiS/ubvNOv+5I+WAAEAa//rBSYFxQAgAFiyDCEiERI5ALAARViwDC8bsQwgPlmwAEVYsAMvG7EDED5ZsAwQsRIBsAorWCHYG/RZsAMQsRkBsAorWCHYG/RZsiAMAxESObAgL7EdAbAKK1gh2Bv0WTAxJQYEIyIkAic1NBIkMzIEFyMCISICBxUUEjMyNjcRITUhBSZG/tywwP7OrQKfASO3+AErH/ku/umq0wPovGSbH/7dAh+8X3KyAUjRMdkBT7bw4wEH/uXpM+z+3zAkARvAAAIAmwAABRcFsAALABUASLIDFhcREjmwAxCwD9AAsABFWLABLxuxASA+WbAARViwAC8bsQAQPlmwARCxDAGwCitYIdgb9FmwABCxDQGwCitYIdgb9FkwMTMRITIEEhcVFAIEBwMRMzISNTU0AiObAb7IAUGyA7D+wMzErtz48doFsLH+w8g4zP6/sgME5PvmAQ7wJuoBDAAAAgBr/+sFcgXFABEAIABIsgQhIhESObAEELAd0ACwAEVYsA0vG7ENID5ZsABFWLAELxuxBBA+WbANELEVAbAKK1gh2Bv0WbAEELEdAbAKK1gh2Bv0WTAxARQCBCMiJAInNTQSJDMyBBIXBzQCIyICFRUUFhYzMhI3BXKm/ti0sv7YqgGlASq0sgEmqAT73K2p32a2bqTYCgLDzv6wuroBTskxywFNwLf+ucYS5AEi/tvoJZPxhgEJ2gAAAgBr/wMFcgXFABQAIwBIsggkJRESObAIELAg0ACwAEVYsBAvG7EQID5ZsABFWLAILxuxCBA+WbAQELEYAbAKK1gh2Bv0WbAIELEgAbAKK1gh2Bv0WTAxARQCBxcHJQYjIiQCJzU0EiQgBBIXBzQCIyICFRUUFhYzMhI1BXKXie+l/tVDPrP+2qoCpwEoAWgBJ6gB+9ytqt5mtW+u2QLGyv69YsCU9Q23AU3LLtABUru3/q/OBewBH/7d7x2X8oQBIPUAAAEAlwAAAu8EjAAGADMAsABFWLAFLxuxBR4+WbAARViwAC8bsQAQPlmyBAAFERI5sAQvsQMBsAorWCHYG/RZMDEhIxEFNSUzAu/z/psCOR8DaXrN0AAAAQBuAAAELASeABkAW7IJGhsREjkAsABFWLARLxuxER4+WbAARViwAC8bsQAQPlmxGAGwCitYIdgb9FmyAhgAERI5sgMAERESObARELEJAbAKK1gh2Bv0WbIMABEREjmyFxEAERI5MDEhITUBNjY1NCYjIgYVIzQ2NjMyFhUUBgcBIQQs/GAB+0Y5aVpne/N514XK6ldu/rECSZ8Buj9jQEhaeGBzvGq3nFqfZv7WAAABAA/+owPyBI0AGQBcshIaGxESOQCwDC+wAEVYsAIvG7ECHj5ZsQABsAorWCHYG/RZsgQAAhESObIFDAIREjmwBS+wDBCxEQGwCitYIdgb9FmwBRCxFwOwCitYIdgb9FmyGRcFERI5MDEBITUhFQEWFhUUBgQjIic3FjMyNjU0JiMjNQKe/boDd/6dq9uQ/vKwx845na2kxKq3SAPJxI/+gBr3sKPzhGe2WLiSlpJ7AAIANf7EBIsEjAAKAA4AUwCwAEVYsAkvG7EJHj5ZsABFWLACLxuxAhA+WbAARViwBi8bsQYQPlmxAAGwCitYIdgb9FmwBhCwBdCwBS+yCAYAERI5sAAQsAzQsg0JAhESOTAxJTMVIxEjESEnATMBIREHA9W2tvL9WAYCpvr9ZAGqF8LD/sUBO5QD+fw2AoAqAAEAZv6gBB4EjAAcAGCyGR0eERI5ALAOL7AARViwAS8bsQEePlmxAwGwCitYIdgb9FmyBwEOERI5sAcvsRkBsAorWCHYG/RZsgUHGRESObAOELETAbAKK1gh2Bv0WbIRExkREjmyHBkTERI5MDETEyEVIQM2NzYSFRQGBiMiJzcWMzI2NTQmIyIGB4daAyn9mi1lhs/thfWl5LVKhL2Pq454U2YbAXUDF9L+qjICAv735JjzgnWyY7OUh6I1OwABAEP+xAQQBIwABgAmALABL7AARViwBS8bsQUePlmxAwGwCitYIdgb9FmyAAMFERI5MDEBASMBITUhBBD9tvMCPv0yA80EBvq+BQXDAAACAHUE0AL3BtwADAAgAH4AsAMvsAbQsAYvQAsPBh8GLwY/Bk8GBV2wAxCxCQawCitYIdgb9FmwBhCwDNCwDC+wBhCwENCwEC+wE9CwEy9ADQ8THxMvEz8TTxNfEwZdsBAQsBbQsBYvsBMQsRoIsAorWCHYG/RZsBAQsR0IsAorWCHYG/RZsBoQsCDQMDEBFAYgJjUzFBYzMjY1ExQGIyImIyIGFSc0NjMyFjMyNjUC97D+3rCvTEZISpBfRziBKh8qaGFFL4gsHiwFsGV7e2U1OjwzAQ9La0cyJRtNbEcyJAAAAQBc/poBTwC1AAMAEgCwBC+wAtCwAi+wAdCwAS8wMQEjETMBT/Pz/poCGwACAE//8AZtBJ0AFAAeAJayFh8gERI5sBYQsAvQALAARViwCi8bsQoePlmwAEVYsAsvG7ELHj5ZsABFWLAALxuxABA+WbAARViwAi8bsQIQPlmwCxCxDQGwCitYIdgb9FmyEAALERI5sBAvsREBsAorWCHYG/RZsAAQsRMBsAorWCHYG/RZsAIQsRUBsAorWCHYG/RZsAoQsRgBsAorWCHYG/RZMDEhIQUiABE1NBI2MwUhFSERIRUhESEFNxEnIgYVFRQWBm39R/6t7P7ahfCbAVMCuP23Afb+CgJM+/TNz4aYmRABNQEMLqwBB4sQxP7yw/7KDwgDFAnAtzWyxwAAAgBz/rQEVASgABgAJABWsh8lJhESObAfELAM0ACwFC+wAEVYsAwvG7EMHj5ZsBQQsQABsAorWCHYG/RZshkUDBESOXywGS8YsQUBsAorWCHYG/RZsAwQsR8BsAorWCHYG/RZMDEFMjY3BiMiAjU0NjYzMgARFRQCBCMiJzcWEzI3NTQmIyIGFRQWAemYvRlyqtH3e9qH8QEUkf7zsp6EL33RsFKIf22HionIvloBEuWZ7YD+0f72zuX+srI8ti8B6XispbSxkoqwAAH/sP5LAY4AzQANAC+yAw4PERI5ALAOL7AARViwBS8bsQUSPlmxCgGwCitYIdgb9FmwDhCwDdCwDS8wMSURFAcGIyInNxYzMjURAY5wW5VGOA4kPXzN/vfIYk8RxgyyAQX//wA5/qMEHASNAQYCTCoAABAAsABFWLACLxuxAh4+WTAx//8Aav6gBCIEjAEGAk4EAAAQALAARViwAS8bsQEePlkwMf//ACz+xASCBIwBBgJN9wAAEwCwAEVYsAkvG7EJHj5ZsA3QMDEA//8AZgAABCQEngEGAkv4AAAQALAARViwES8bsREePlkwMf//AGP+xAQwBIwBBgJPIAAAEACwAEVYsAUvG7EFHj5ZMDH//wA1/+sEWASgAQYCZdMAABMAsABFWLAKLxuxCh4+WbAR0DAxAP//AG//7AQxBbcDBgAa+gAAEwCwAEVYsAAvG7EAID5ZsBXQMDEA//8AWf60BDoEoAEGAlPmAAATALAARViwDC8bsQwePlmwH9AwMQD//wBo/+wEIgXEAwYAHAAAABkAsABFWLAVLxuxFSA+WbAb0LAVELAl0DAxAP//AOMAAAM7BIwABgJKTAD///+1/ksBkwQ6AgYAnAAA////tf5LAZMEOgIGAJwAAP//AI8AAAGCBDoABgCNAAD////7/lwBggQ6ACYAjQAAAAYApNIK//8AjwAAAYIEOgAGAI0AAAABAHb/6wQWBJwAIQBosgEiIxESOQCwAEVYsBUvG7EVHj5ZsABFWLAfLxuxHxA+WbAARViwEC8bsRAQPlmwHxCxAgGwCitYIdgb9FmyCh8VERI5sAovsBnQsQgDsAorWCHYG/RZsBUQsQ0BsAorWCHYG/RZMDElFjMyNjU0JiMjNRMmIyIVESMRNjYzMhYXAxYWFRQGIyInAetLSE1cfHRUykZRse8B0c94zWj5oarZr3xs2zFlUlhHowEBOfn9HALw19Vhb/7UF6SBr8o2AAIAYv/rBIUEoAANABoASLIDGxwREjmwAxCwF9AAsABFWLAKLxuxCh4+WbAARViwAy8bsQMQPlmwChCxEQGwCitYIdgb9FmwAxCxFgGwCitYIdgb9FkwMQEQACMiJgI1EAAzMhYSBzQmIAYVFRQWMzI2NwSF/uPznvOCAR/yn/KB8pv+9pmahoWXAgI+/un+xI4BDMcBFgE+jv7zp7jHyLostc3FtAABADoAAAPqBbAABgAzALAARViwBS8bsQUgPlmwAEVYsAEvG7EBED5ZsAUQsQMBsAorWCHYG/RZsgADBRESOTAxAQEjASE1IQPq/dT0Aiz9RAOwBSn61wTtwwACAHz/7ARGBgAADwAaAGayExscERI5sBMQsAzQALAJL7AARViwDC8bsQwcPlmwAEVYsAMvG7EDED5ZsABFWLAGLxuxBhA+WbIFDAMREjmyCgwDERI5sAwQsRMBsAorWCHYG/RZsAMQsRgBsAorWCHYG/RZMDEBFAIjIicHIxEzETYzMhIRJzQmIyIHERYzMjYERvPHwG0R0vNpsszw84t7mkRHmXqKAhH0/s+OegYA/dJ8/tb++gimu4X+N4e8AAABAFD/7AQABE4AHQBNshceHxESOQCwAEVYsBAvG7EQHD5ZsABFWLAILxuxCBA+WbEAAbAKK1gh2Bv0WbIDCBAREjmyFBAIERI5sBAQsRcBsAorWCHYG/RZMDElMjY3Mw4CIyIANTU0NjYzMhYXIyYmIyIGFRUUFgJCWnoG5AR6ynTm/vJ64ZjD9AbkB3hceYWFrmlPZrBkASv+GZ77h+S0X3azshutsAACAE//7AQXBgAAEQAcAGayGh0eERI5sBoQsATQALAHL7AARViwBC8bsQQcPlmwAEVYsA0vG7ENED5ZsABFWLAJLxuxCRA+WbIGBA0REjmyCwQNERI5sA0QsRUBsAorWCHYG/RZsAQQsRoBsAorWCHYG/RZMDETNDY2MzIXETMRIycGIyImJjU3FBYzMjcRJiMiBk9wzYKsavPTEWy7fst08417lEZGkn2NAiaf/Yx3Ain6AHWJjP2bAZ3CgQHXfcEAAAIAT/5WBBcETgAbACYAhrIfJygREjmwHxCwDNAAsABFWLAELxuxBBw+WbAARViwBy8bsQccPlmwAEVYsAwvG7EMEj5ZsABFWLAYLxuxGBA+WbIGBBgREjmwDBCxEgGwCitYIdgb9FmyEBIYERI5shYEGBESObAYELEfAbAKK1gh2Bv0WbAEELEkAbAKK1gh2Bv0WTAxEzQ2NjMyFzczERQAIyImJzcWMzI2NTUGIyImJjcUFjMyNxEmIyIGT23Nhb9pENH+++9VuUk1gpCOg2quf8xy8494lUZFlHyNAiag+42Gcvwc9v72Ly2wTJybFneM/J2fwIEB2XvBAAIATP/sBFUETgAPABkARbIEGhsREjmwBBCwF9AAsABFWLAELxuxBBw+WbAARViwDC8bsQwQPlmxEgGwCitYIdgb9FmwBBCxFwGwCitYIdgb9FkwMRM0NjYzMgAVFRQGBiMiADUXFBYyNjU0JiIGTILrluYBIH/tmOb+4fKV/JOX+JUCJ5/9i/7N/A2d/I0BMf4JoMTEtZ/FxgACAHz+YAREBE4AEAAbAHCyGRwdERI5sBkQsA3QALAARViwDS8bsQ0cPlmwAEVYsAovG7EKHD5ZsABFWLAHLxuxBxI+WbAARViwBC8bsQQQPlmyBg0EERI5sgsNBBESObANELEUAbAKK1gh2Bv0WbAEELEZAbAKK1gh2Bv0WTAxARQGBiMiJxEjETMXNjMyEhcHNCYjIgcRFjMyNgREb8iBsWzz2Q5susHvCvGRfJJERZN4kwIRnv2KdP4ABdpxhf7r7Cefwnj+F3jDAAACAE/+YAQWBE4AEAAbAG2yGRwdERI5sBkQsATQALAARViwBC8bsQQcPlmwAEVYsAcvG7EHHD5ZsABFWLAJLxuxCRI+WbAARViwDS8bsQ0QPlmyBgQNERI5sgsEDRESObEUAbAKK1gh2Bv0WbAEELEZAbAKK1gh2Bv0WTAxEzQ2NjMyFzczESMRBiMiAic3FBYzMjcRJiMiBk9vzYa3axHS82qqvvYL8pN4kEZIjH6PAiai/IqCbvomAfxwARziJ57FdgH0c8YAAAIAU//sBAsETgAWAB4Af7IIHyAREjmwCBCwF9AAsABFWLAILxuxCBw+WbAARViwAC8bsQAQPlmyGwgAERI5sBsvtL8bzxsCXbRfG28bAnG0HxsvGwJxso8bAV207xv/GwJxsQwHsAorWCHYG/RZsAAQsRABsAorWCHYG/RZsAgQsRcBsAorWCHYG/RZMDEFIgA1NTQ2NjMyEhUVIRYWMzI2NxcGBgMiBgchNTQmAnby/s994ovd8f0+D6mNVZIxOj+9p2Z8EAHQcxQBKPchnvmL/vT3e4WdLyCmMjkDn418GnB/AAIAUf5WBAQETgAZACQAhrIiJSYREjmwIhCwC9AAsABFWLADLxuxAxw+WbAARViwBi8bsQYcPlmwAEVYsAsvG7ELEj5ZsABFWLAXLxuxFxA+WbIFAxcREjmwCxCxEQGwCitYIdgb9FmyDxEXERI5shUDFxESObAXELEdAbAKK1gh2Bv0WbADELEiAbAKK1gh2Bv0WTAxEzQSMzIXNzMRFAAjIiYnNxYzMjY1NQYjIgI3FBYzMjcRJiMiBlHnw71rEdD++u1Xrzc1dYOOgmquvurygXOXQ0SUdoACJv0BK4Zy/BDy/v4uIbA/lpQidgEv9qi3hQHRf7X//wBbAAACsgW1AAYAFbMAAAMAXf/vBLcEnQAdACYAMgBssiwzNBESObAsELAT0LAsELAf0ACwAEVYsA0vG7ENHj5ZsABFWLAALxuxABA+WbAARViwGi8bsRoQPlmyFA0aERI5sAAQsB6wCitY2BvcWbIhDRoREjmyKg0aERI5sA0QsDCwCitY2BvcWTAxBSImNTQ2NzcnJjU0NjMyFhUUBwcXNjUzFAcXIScGJzI3AwcGFRQWAxQWFzc2NTQmIyIGAfu65FJyMkBcvpSZu51I6DrUgMn+9Eqbv3RY/UVCXBc5Kj9JQjczPxGqhVWGTiJFaXN5mqB7kmwy8GOG3KDPTF3DLQEEMDBIP0oCwylKKis1QSw6PAABAAMAAAOeBI0ADQA+sgEODxESOQCwAEVYsAovG7EKHj5ZsABFWLAELxuxBBA+WbECAbAKK1gh2Bv0WbIGCgQREjmyDAoEERI5MDEBBxEhFSERBzU3ETMRNwJt+gIr/OJ9ffP6Ap1M/nHCAggmkyYB8v5XTAAAAv/xAAAGAwSNAA8AEgCKsgUTFBESObAFELAR0ACwAEVYsAovG7EKHj5ZsABFWLAELxuxBBA+WbAARViwCC8bsQgQPlmyDwoEERI5fLAPLxixAAGwCitYIdgb9FmwBBCxAgGwCitYIdgb9FmyEQoEERI5sBEvsQYBsAorWCHYG/RZsAoQsQwBsAorWCHYG/RZshIKBBESOTAxASETIRUhAyEDIQEhFSETIQUhAwWY/kUMAhr8/Qr+goP+/AJtA3f99gsBwvxAARYUAf7+wsABB/75BI3B/vT5AgUAAAIAdgAAA9IEjQAMABUAWbIJFhcREjmwCRCwD9AAsABFWLAALxuxAB4+WbAARViwCy8bsQsQPlmyAgALERI5sAIvsg8ACxESObAPL7EJAbAKK1gh2Bv0WbACELENAbAKK1gh2Bv0WTAxEzMVMzIWFRQGByMVIxMRMzI2NTQmJ3bzldf99tec8/OZa3N2YwSNt9CqrsoB4wMS/pRfVVJlAQADAE//yQRvBLoAFgAfACgAarIGKSoREjmwBhCwHNCwBhCwJdAAsABFWLASLxuxEh4+WbAARViwBi8bsQYQPlmyGRIGERI5shoSBhESObASELEcAbAKK1gh2Bv0WbIiEgYREjmyIwYSERI5sAYQsSUBsAorWCHYG/RZMDEBFhcVEAAjIicHIzcmAzU0EjYzMhc3MwEUFwEmIyIGFSE0JwEWMzI2NQPkhwT+3+2eekykh5ABhfCbo3tIpPzYKAGbQ2KGmAI8JP5nQl+IlAP7mvRB/vj+zEduw5sBBDSsAQeLTGn9coFZAlI0wLd3Wf2yMMO2AAIAMQAABNcEjQATABcAjbIFGBkREjmwBRCwFNAAsABFWLAMLxuxDB4+WbAARViwEC8bsRAePlmwAEVYsAIvG7ECED5ZsABFWLAGLxuxBhA+WbITDAIREjmwEy+yDxMBXbEADrAKK1gh2Bv0WbIVDAIREjmwFS+xBAGwCitYIdgb9FmwABCwCNCwExCwCtCwExCwDtCwABCwFtAwMQEjESMRIREjESM1MzUzFSE1MxUzASE1IQTXWvL98/NaWvMCDfJa/KcCDf3zA0/8sQHb/iUDT6qUlJSU/qWxAAABAHb+SwRnBI0AEwBbsgIUFRESOQCwAEVYsAwvG7EMHj5ZsABFWLAPLxuxDx4+WbAARViwAC8bsQASPlmwAEVYsAovG7EKED5ZsAAQsQUBsAorWCHYG/RZsgkMABESObIODAAREjkwMQEiJzcWMzI1NQERIxEzAREzEQYGAwdHOA4kPnz99fPzAgzyAbj+SxHGDLI5Axr85QSN/OQDHPsyssIA//8ARwIJAlQCzQIGABEAAAAC//cAAATwBbAADwAdAIWyEB4fERI5sBAQsAbQALAARViwBS8bsQUgPlmwAEVYsAAvG7EAED5ZsgMABRESObADL7LPAwFdsj8DAXGybwMBcbIfAwFxsp8DAV2yDwMBcrECB7AKK1gh2Bv0WbAR0LAAELESAbAKK1gh2Bv0WbAFELEbAbAKK1gh2Bv0WbADELAd0DAxMxEjNTMRITIEEhUVFAIEIxMjETMyNjU1NCYjIxEzsru7Aa7BASukpf7PxT/lo8vVzsSx5QKMqgJ6rP7EzEnP/saqAoz+Pv3wRu36/lIAAv/3AAAE8AWwAA8AHQCFshAeHxESObAQELAG0ACwAEVYsAUvG7EFID5ZsABFWLAALxuxABA+WbIDAAUREjmwAy+yzwMBXbI/AwFxsm8DAXGyHwMBcbKfAwFdsg8DAXKxAgewCitYIdgb9FmwEdCwABCxEgGwCitYIdgb9FmwBRCxGwGwCitYIdgb9FmwAxCwHdAwMTMRIzUzESEyBBIVFRQCBCMTIxEzMjY1NTQmIyMRM7K7uwGuwQErpKX+z8U/5aPL1c7EseUCjKoCeqz+xMxJz/7GqgKM/j798Ebt+v5SAAH/1AAABBYGAAAYAHayDBkaERI5ALAVL7AARViwBC8bsQQcPlmwAEVYsAcvG7EHED5ZsABFWLAPLxuxDxA+WbIvFQFdsg8VAV2yGA8VERI5sBgvsQAHsAorWCHYG/RZsgIEDxESObAEELEMAbAKK1gh2Bv0WbAAELAR0LAYELAT0DAxASMRNjMgExEjETQmIyIHESMRIzUzNTMVMwJx53e2AVoF82Fekkjzw8Pz5wTH/v2K/nX9PQK6cF2C/PsEx6qPjwABAC0AAASwBbAADwBOALAARViwCi8bsQogPlmwAEVYsAIvG7ECED5Zsg8KAhESObAPL7EAB7AKK1gh2Bv0WbAE0LAPELAG0LAKELEIAbAKK1gh2Bv0WbAM0DAxASMRIxEjNTMRITUhFSERMwO5z/vT0/4+BIP+Os8DEvzuAxKqASjMzP7YAAH/6P/sAoUFQQAcAHWyAB0eERI5ALAARViwGy8bsRscPlmwAEVYsBEvG7ERED5ZsBsQsAHQsBsQsRgBsAorWCHYG/RZsATQsBsQsBfQsBcvsAXQsAUvsBcQsRQHsAorWCHYG/RZsAjQsBEQsQwBsAorWCHYG/RZsBsQsBzQsBwvMDEBETMVIxUzFSMRFBYzMjcVBiMgEREjNTM1IzUzEQGtv7/Y2DE/KitTTf7o0tKysgVB/vm0par+8z43CrwXATUBFqqltAEHAP//ABIAAAVCBzYCJgAlAAABBwBEASMBNgATALAARViwBC8bsQQgPlmwDNwwMQD//wASAAAFQgc2AiYAJQAAAQcAdQHCATYAEwCwAEVYsAUvG7EFID5ZsA3cMDEA//8AEgAABUIHNwImACUAAAEHAJ4AwwE2ABMAsABFWLAELxuxBCA+WbAP3DAxAP//ABIAAAVCBywCJgAlAAABBwClAMUBNwAJALAEL7AW3DAxAP//ABIAAAVCBwICJgAlAAABBwBqAO4BNgAWALAARViwBC8bsQQgPlmwEtywG9AwMf//ABIAAAVCB5QCJgAlAAABBwCjAVgBagAMALAEL7AQ3LAV0DAx//8AEgAABUIHsQImACUAAAAHAicBXgEc//8AZv48BOsFxAImACcAAAAHAHkByf/7//8AlAAABEwHPQImACkAAAEHAEQA6AE9ABMAsABFWLAGLxuxBiA+WbAN3DAxAP//AJQAAARMBz0CJgApAAABBwB1AYcBPQATALAARViwBi8bsQYgPlmwDtwwMQD//wCUAAAETAc+AiYAKQAAAQcAngCIAT0AEwCwAEVYsAYvG7EGID5ZsBDcMDEA//8AlAAABEwHCQImACkAAAEHAGoAswE9ABYAsABFWLAGLxuxBiA+WbAT3LAc0DAx////yAAAAaAHPQImAC0AAAEHAET/lwE9ABMAsABFWLACLxuxAiA+WbAF3DAxAP//AKMAAAJ9Bz0CJgAtAAABBwB1ADUBPQATALAARViwAy8bsQMgPlmwBtwwMQD////LAAACegc+AiYALQAAAQcAnv83AT0AEwCwAEVYsAIvG7ECID5ZsAjcMDEA////vwAAAoUHCQImAC0AAAEHAGr/YgE9ABYAsABFWLACLxuxAiA+WbAL3LAU0DAx//8AlAAABRcHLAImADIAAAEHAKUA7gE3AAkAsAUvsBXcMDEA//8AZv/sBR4HNgImADMAAAEHAEQBOgE2ABMAsABFWLAMLxuxDCA+WbAg3DAxAP//AGb/7AUeBzYCJgAzAAABBwB1AdkBNgATALAARViwDS8bsQ0gPlmwIdwwMQD//wBm/+wFHgc3AiYAMwAAAQcAngDaATYAEwCwAEVYsAwvG7EMID5ZsCPcMDEA//8AZv/sBR4HLAImADMAAAEHAKUA3AE3ABMAsABFWLANLxuxDSA+WbAi3DAxAP//AGb/7AUeBwICJgAzAAABBwBqAQUBNgAWALAARViwDC8bsQwgPlmwJtywL9AwMf//AH3/7AS9BzYCJgA5AAABBwBEAREBNgATALAARViwCS8bsQkgPlmwEtwwMQD//wB9/+wEvQc2AiYAOQAAAQcAdQGwATYACQCwAC+wE9wwMQD//wB9/+wEvQc3AiYAOQAAAQcAngCxATYAEwCwAEVYsAkvG7EJID5ZsBXcMDEA//8Aff/sBL0HAgImADkAAAEHAGoA3AE2ABYAsABFWLAJLxuxCSA+WbAY3LAh0DAx//8ABwAABNYHNgImAD0AAAEHAHUBhwE2ABMAsABFWLABLxuxASA+WbAL3DAxAP//AFr/7AP7BgACJgBFAAABBwBEAK0AAAATALAARViwFy8bsRccPlmwK9wwMQD//wBa/+wD+wYAAiYARQAAAQcAdQFMAAAACQCwFy+wLNwwMQD//wBa/+wD+wYBAiYARQAAAQYAnk0AABMAsABFWLAXLxuxFxw+WbAu3DAxAP//AFr/7AP7BfYCJgBFAAABBgClTwEAEwCwAEVYsBcvG7EXHD5ZsC3cMDEA//8AWv/sA/sFzAImAEUAAAEGAGp4AAAWALAARViwFy8bsRccPlmwMdywOtAwMf//AFr/7AP7Bl4CJgBFAAABBwCjAOIANAAWALAARViwFy8bsRccPlmwL9ywN9AwMf//AFr/7AP7BnwCJgBFAAAABwInAOj/5///AE/+PAP1BE4CJgBHAAAABwB5AT3/+///AFP/7AQLBgACJgBJAAABBwBEAKEAAAATALAARViwCC8bsQgcPlmwH9wwMQD//wBT/+wECwYAAiYASQAAAQcAdQFAAAAACQCwCC+wINwwMQD//wBT/+wECwYBAiYASQAAAQYAnkEAABMAsABFWLAILxuxCBw+WbAi3DAxAP//AFP/7AQLBcwCJgBJAAABBgBqbAAAFgCwAEVYsAgvG7EIHD5ZsCXcsC7QMDH///+0AAABjAX5AiYAjQAAAQYARIP5ABMAsABFWLACLxuxAhw+WbAF3DAxAP//AI8AAAJpBfkCJgCNAAABBgB1IfkAEwCwAEVYsAMvG7EDHD5ZsAbcMDEA////twAAAmYF+gImAI0AAAEHAJ7/I//5ABMAsABFWLACLxuxAhw+WbAI3DAxAP///6sAAAJxBcUCJgCNAAABBwBq/07/+QAWALAARViwAi8bsQIcPlmwC9ywFNAwMf//AHkAAAP4BfYCJgBSAAABBgClVQEACQCwAy+wHNwwMQD//wBP/+wEPQYAAiYAUwAAAQcARAC2AAAAEwCwAEVYsAQvG7EEHD5ZsBzcMDEA//8AT//sBD0GAAImAFMAAAEHAHUBVQAAAAkAsAQvsB3cMDEA//8AT//sBD0GAQImAFMAAAEGAJ5WAAATALAARViwBC8bsQQcPlmwH9wwMQD//wBP/+wEPQX2AiYAUwAAAQYApVgBAAkAsAQvsCbcMDEA//8AT//sBD0FzAImAFMAAAEHAGoAgQAAABYAsABFWLAELxuxBBw+WbAi3LAr0DAx//8Ad//sA/cGAAImAFkAAAEHAEQArwAAABMAsABFWLAHLxuxBxw+WbAS3DAxAP//AHf/7AP3BgACJgBZAAABBwB1AU4AAAAJALAGL7AT3DAxAP//AHf/7AP3BgECJgBZAAABBgCeTwAAEwCwAEVYsAcvG7EHHD5ZsBXcMDEA//8Ad//sA/cFzAImAFkAAAEGAGp6AAAWALAARViwBy8bsQccPlmwGNywIdAwMf//AAz+SwPWBgACJgBdAAABBwB1ARYAAAAJALABL7AS3DAxAP//AAz+SwPWBcwCJgBdAAABBgBqQgAAFgCwAEVYsA8vG7EPHD5ZsBfcsCDQMDH//wASAAAFQgbkAiYAJQAAAQcAcAC+AToAEwCwAEVYsAQvG7EEID5ZsAzcMDEA//8AWv/sA/sFrgImAEUAAAEGAHBIBAAJALAXL7Aq3DAxAP//ABIAAAVCBxwCJgAlAAABBwChAPYBNgATALAARViwBC8bsQQgPlmwDtwwMQD//wBa/+wD+wXmAiYARQAAAQcAoQCAAAAAEwCwAEVYsBcvG7EXHD5ZsC3cMDEAAAIAEv5SBUIFsAAWABkAdrIZGhsREjmwGRCwFtAAsABFWLAWLxuxFiA+WbAARViwFC8bsRQQPlmwAEVYsAEvG7EBED5ZsABFWLAMLxuxDBI+WbEHA7AKK1gh2Bv0WbABELAR0LARL7IXFBYREjmwFy+xEwGwCitYIdgb9FmyGRYUERI5MDEBASMGBhUUMzI3FwYjIiY1NDcDIQMhAQMhAwMbAic+V0pHLC4VSVxfdJVz/cx2/vkCJmIBptMFsPpQOF4xRBeOLG5bjWIBSf6tBbD8bwJcAAACAFr+UgP7BE4ALQA4AKqyFzk6ERI5sBcQsC/QALAARViwFy8bsRccPlmwAEVYsCkvG7EpEj5ZsABFWLAELxuxBBA+WbAARViwHi8bsR4QPlmwANCwAC+yAhcEERI5sgsXBBESObALL7AXELEPAbAKK1gh2Bv0WbISCw8REjlACQwSHBIsEjwSBF2wKRCxJAOwCitYIdgb9FmwBBCxLgGwCitYIdgb9FmwCxCxMgGwCitYIdgb9FkwMSUmJwYjIiY1NCQzMzU0JiMiBhUjNDY2MzIWFxEUFxUjBgYVFDMyNxcGIyImNTQDMjY3NSMiBhUUFgL/Cw10qKPOAQHvlV5gU2rzdst9vuIDKSpXSkcsLhVJXF90dkh/IIOHiF0HGUV5uomtuUdUZVNAWZtYv63+GJJXETheMUQXjixuW4wBCEY7zF5WRlP//wBm/+wE6wdLAiYAJwAAAQcAdQHAAUsACQCwDC+wINwwMQD//wBP/+wD9QYAAiYARwAAAQcAdQEpAAAACQCwDy+wH9wwMQD//wBm/+wE6wdMAiYAJwAAAQcAngDBAUsAEwCwAEVYsAwvG7EMID5ZsCDcMDEA//8AT//sA/UGAQImAEcAAAEGAJ4qAAATALAARViwDy8bsQ8cPlmwH9wwMQD//wBm/+wE6wcpAiYAJwAAAQcAogGnAVQAEwCwAEVYsAwvG7EMID5ZsCbcMDEA//8AT//sA/UF3gImAEcAAAEHAKIBEAAJABMAsABFWLAPLxuxDxw+WbAl3DAxAP//AGb/7ATrB0wCJgAnAAABBwCfANgBSwAJALAML7Ai3DAxAP//AE//7AP1BgECJgBHAAABBgCfQQAACQCwDy+wIdwwMQD//wCUAAAE0gc+AiYAKAAAAQcAnwBnAT0ACQCwAS+wGtwwMQD//wBP/+wFWwYCACYASAAAAQcBugQBBPwABgCwHi8wMf//AJQAAARMBusCJgApAAABBwBwAIMBQQATALAARViwBi8bsQYgPlmwDdwwMQD//wBT/+wECwWuAiYASQAAAQYAcDwEAAkAsAgvsB7cMDEA//8AlAAABEwHIwImACkAAAEHAKEAuwE9ABMAsABFWLAGLxuxBiA+WbAP3DAxAP//AFP/7AQLBeYCJgBJAAABBgChdAAAEwCwAEVYsAgvG7EIHD5ZsCHcMDEA//8AlAAABEwHGwImACkAAAEHAKIBbgFGABMAsABFWLAGLxuxBiA+WbAU3DAxAP//AFP/7AQLBd4CJgBJAAABBwCiAScACQATALAARViwCC8bsQgcPlmwJtwwMQAAAQCU/lIETAWwABsAhLIRHB0REjkAsABFWLAWLxuxFiA+WbAARViwDy8bsQ8SPlmwAEVYsAQvG7EEED5ZsABFWLAULxuxFBA+WbIaFBYREjmwGi+xAQGwCitYIdgb9FmwFBCxAgGwCitYIdgb9FmwA9CwDxCxCgOwCitYIdgb9FmwFhCxGAGwCitYIdgb9FkwMQEhESEVIwYGFRQzMjcXBiMiJjU0NyERIRUhESED5/2qArtvV0pHLC4VSVxfdIf9kwOx/UwCVgKK/kDKOF4xRBeOLG5bhl8FsMz+bgAAAgBT/m0ECwROACMAKwCpshEsLRESObARELAk0ACwAEVYsBkvG7EZHD5ZsABFWLAMLxuxDBI+WbAARViwES8bsREQPlmyAhEZERI5sAwQsQcDsAorWCHYG/RZsigZERESObAoL7QfKC8oAnG0vyjPKAJdso8oAV20XyhvKAJxtO8o/ygCcbEdB7AKK1gh2Bv0WbARELEhAbAKK1gh2Bv0WbIjGREREjmwGRCxJAGwCitYIdgb9FkwMSUGBwYGFRQzMjcXBiMiJjU0NyYAJzU0NjYzMhIRFSEWFjMyNwEiBgchNSYmA/pJcVdKRywuFUlcX3RQz/77Bn3ii93x/T0LnXenaf7FZHsRAc8IcrhqMzheMUQXjixuW2ZSDQET1zqi/47+5v7+YoachwJWjH0Sen3//wCUAAAETAc+AiYAKQAAAQcAnwCfAT0AEwCwAEVYsAYvG7EGID5ZsBHcMDEA//8AU//sBAsGAQImAEkAAAEGAJ9YAAAJALAIL7Ai3DAxAP//AGr/7ATwB0wCJgArAAABBwCeAL4BSwATALAARViwCy8bsQsgPlmwIdwwMQD//wBS/lYEDAYBAiYASwAAAQYAnkAAABMAsABFWLADLxuxAxw+WbAn3DAxAP//AGr/7ATwBzECJgArAAABBwChAPEBSwATALAARViwCy8bsQsgPlmwItwwMQD//wBS/lYEDAXmAiYASwAAAQYAoXMAABMAsABFWLADLxuxAxw+WbAo3DAxAP//AGr/7ATwBykCJgArAAABBwCiAaQBVAATALAARViwCy8bsQsgPlmwJ9wwMQD//wBS/lYEDAXeAiYASwAAAQcAogEmAAkAEwCwAEVYsAMvG7EDHD5ZsC3cMDEA//8Aav3zBPAFxAImACsAAAAHAboB4/6M//8AUv5WBAwGqQImAEsAAAEHAjQBJwB+AAkAsAMvsCncMDEA//8AlAAABRgHPgImACwAAAEHAJ4A4gE9ABMAsABFWLAHLxuxByA+WbAQ3DAxAP//AHkAAAP4B14CJgBMAAABBwCeABcBXQAJALAQL7AT3DAxAP///7MAAAKQBzMCJgAtAAABBwCl/zkBPgATALAARViwAy8bsQMgPlmwB9wwMQD///+fAAACfAXvAiYAjQAAAQcApf8l//oACQCwAi+wD9wwMQD////NAAACfAbrAiYALQAAAQcAcP8yAUEAEwCwAEVYsAIvG7ECID5ZsAXcMDEA////uQAAAmgFpwImAI0AAAEHAHD/Hv/9ABMAsABFWLACLxuxAhw+WbAF3DAxAP///98AAAJlByMCJgAtAAABBwCh/2oBPQATALAARViwAi8bsQIgPlmwB9wwMQD////LAAACUQXfAiYAjQAAAQcAof9W//kAEwCwAEVYsAIvG7ECHD5ZsAfcMDEA//8AF/5YAZ8FsAImAC0AAAAGAKTuBv//AAD+UgGQBdUCJgBNAAAABgCk1wD//wCdAAABowcbAiYALQAAAQcAogAcAUYAEwCwAEVYsAIvG7ECID5ZsAzcMDEA//8Ao//sBiYFsAAmAC0AAAAHAC4CQgAA//8Aff5LA5AF1QAmAE0AAAAHAE4CCwAA//8ALf/sBKsHNwImAC4AAAEHAJ4BaAE2ABMAsABFWLAALxuxACA+WbAU3DAxAP///7X+SwJrBd8CJgCcAAABBwCe/yj/3gATALAARViwDC8bsQwcPlmwEdwwMQD//wCU/kQFGAWwAiYALwAAAAcBugGd/t3//wB9/i8ENgYAAiYATwAAAAcBugEt/sj//wCUAAAEJgc2AiYAMAAAAQcAdQApATYAEwCwAEVYsAUvG7EFID5ZsAjcMDEA//8AigAAAmIHkQImAFAAAAEHAHUAGgGRABMAsABFWLADLxuxAyI+WbAG3DAxAP//AJT+AwQmBbACJgAwAAAABwG6AW3+nP//AFX+AwF/BgACJgBQAAAABwG6ABD+nP//AJQAAAQmBbECJgAwAAABBwG6AgoEqwAQALAARViwCi8bsQogPlkwMf//AIwAAALnBgIAJgBQAAABBwG6AY0E/AAQALAARViwCC8bsQgiPlkwMf//AJQAAAQmBbACJgAwAAAABwCiAcr91P//AIwAAALrBgAAJgBQAAAABwCiAWT9r///AJQAAAUXBzYCJgAyAAABBwB1AesBNgATALAARViwCC8bsQggPlmwDNwwMQD//wB5AAAD+AYAAiYAUgAAAQcAdQFSAAAACQCwAy+wE9wwMQD//wCU/f8FFwWwAiYAMgAAAAcBugHc/pj//wB5/gMD+AROAiYAUgAAAAcBugFB/pz//wCUAAAFFwc3AiYAMgAAAQcAnwEDATYAEwCwAEVYsAYvG7EGID5ZsA/cMDEA//8AeQAAA/gGAQImAFIAAAEGAJ9qAAAJALADL7AV3DAxAP///6UAAAP4BgMCJgBSAAABBwG6/2AE/QAQALAARViwFS8bsRUiPlkwMf//AGb/7AUeBuQCJgAzAAABBwBwANUBOgATALAARViwDC8bsQwgPlmwINwwMQD//wBP/+wEPQWuAiYAUwAAAQYAcFEEAAkAsAQvsBvcMDEA//8AZv/sBR4HHAImADMAAAEHAKEBDQE2ABMAsABFWLAMLxuxDCA+WbAi3DAxAP//AE//7AQ9BeYCJgBTAAABBwChAIkAAAATALAARViwBC8bsQQcPlmwHtwwMQD//wBm/+wFHgc1AiYAMwAAAQcApgFjATYAFgCwAEVYsA0vG7ENID5ZsCHcsCXQMDH//wBP/+wEPQX/AiYAUwAAAQcApgDfAAAAFgCwAEVYsAQvG7EEHD5ZsB3csCHQMDH//wCUAAAE3gc2AiYANgAAAQcAdQFxATYACQCwBC+wGtwwMQD//wB8AAAC9QYAAiYAVgAAAQcAdQCtAAAACQCwCy+wENwwMQD//wCU/gME3gWwAiYANgAAAAcBugFu/pz//wBP/gMCtAROAiYAVgAAAAcBugAK/pz//wCUAAAE3gc3AiYANgAAAQcAnwCJATYACQCwBC+wHNwwMQD//wA4AAAC+gYBAiYAVgAAAQYAn8YAAAkAsAsvsBLcMDEA//8ASv/sBIoHNgImADcAAAEHAHUBjgE2AAkAsAkvsCrcMDEA//8AS//sA8oGAAImAFcAAAEHAHUBOgAAAAkAsAkvsCncMDEA//8ASv/sBIoHNwImADcAAAEHAJ4AjwE2ABMAsABFWLAJLxuxCSA+WbAq3DAxAP//AEv/7APKBgECJgBXAAABBgCeOwAAEwCwAEVYsAkvG7EJHD5ZsCncMDEA//8ASv5BBIoFxAImADcAAAAHAHkBnQAA//8AS/44A8oETgImAFcAAAAHAHkBRP/3//8ASv35BIoFxAImADcAAAAHAboBif6S//8AS/3vA8oETgImAFcAAAAHAboBMP6I//8ASv/sBIoHNwImADcAAAEHAJ8ApgE2AAkAsAkvsCzcMDEA//8AS//sA8oGAQImAFcAAAEGAJ9SAAAJALAJL7Ar3DAxAP//AC39/ASwBbACJgA4AAAABwG6AXf+lf//AAj9+QJyBUECJgBYAAAABwG6AMj+kv//AC3+RASwBbACJgA4AAAABwB5AYsAA///AAj+QQKlBUECJgBYAAAABwB5ANwAAP//AC0AAASwBzcCJgA4AAABBwCfAJgBNgATALAARViwBi8bsQYgPlmwDdwwMQD//wAI/+wDJwaDACYAWAAAAAcBugHNBX3//wB9/+wEvQcsAiYAOQAAAQcApQCzATcAEwCwAEVYsBAvG7EQID5ZsBTcMDEA//8Ad//sA/cF9gImAFkAAAEGAKVRAQATALAARViwDS8bsQ0cPlmwFNwwMQD//wB9/+wEvQbkAiYAOQAAAQcAcACsAToACQCwAC+wEdwwMQD//wB3/+wD9wWuAiYAWQAAAQYAcEoEABMAsABFWLAGLxuxBhw+WbAS3DAxAP//AH3/7AS9BxwCJgA5AAABBwChAOQBNgATALAARViwCS8bsQkgPlmwFNwwMQD//wB3/+wD9wXmAiYAWQAAAQcAoQCCAAAAEwCwAEVYsAcvG7EHHD5ZsBTcMDEA//8Aff/sBL0HlAImADkAAAEHAKMBRgFqAAwAsAAvsBbcsBvQMDH//wB3/+wD9wZeAiYAWQAAAQcAowDkADQADACwBi+wFtywG9AwMf//AH3/7AS9BzUCJgA5AAABBwCmAToBNgAWALAARViwEC8bsRAgPlmwE9ywF9AwMf//AHf/7AQuBf8CJgBZAAABBwCmANgAAAAMALAGL7AT3LAV0DAxAAEAff6JBL0FsAAfAFmyHCAhERI5ALAARViwGC8bsRggPlmwAEVYsBMvG7ETED5ZsABFWLAOLxuxDhg+WbIEExgREjmxCQOwCitYIdgb9FmwExCxHAGwCitYIdgb9FmwGBCwH9AwMQERFAYHBgYVFDMyNxcGIyImNTQ3IAA1ETMRFBYzIBERBL2Ffj1PRywuFUlcX3Q2/wD+2/yUkAEkBbD8MpjkPSlZN0QXjixuW1VFAQzrA838MpKaATQDxgABAHf+UgP3BDoAHwBoshogIRESOQCwAEVYsBcvG7EXHD5ZsABFWLASLxuxEhA+WbAARViwHy8bsR8QPlmwAEVYsAovG7EKEj5ZsQUDsAorWCHYG/RZsB8QsA/QsA8vsBIQsRoBsAorWCHYG/RZsBcQsB3QMDEhBgYVFDMyNxcGIyImNTQ3JwYjIiY1ETMRFDMyNxEzEQPiV0pHLC4VSVxfdJIFa8WwtfOrsT7zOF4xRBeOLG5bjGFifs7DAr39Rs5/Awn7xv//ADAAAAblBzcCJgA7AAABBwCeAagBNgATALAARViwDC8bsQwgPlmwD9wwMQD//wAhAAAFzAYBAiYAWwAAAQcAngEKAAAAEwCwAEVYsAsvG7ELHD5ZsBHcMDEA//8ABwAABNYHNwImAD0AAAEHAJ4AiAE2ABMAsABFWLABLxuxASA+WbAL3DAxAP//AAz+SwPWBgECJgBdAAABBgCeFwAAEwCwAEVYsA8vG7EPHD5ZsBTcMDEA//8ABwAABNYHAgImAD0AAAEHAGoAswE2ABYAsABFWLAILxuxCCA+WbAQ3LAZ0DAx//8AUAAABIwHNgImAD4AAAEHAHUBgwE2ABMAsABFWLAHLxuxByA+WbAM3DAxAP//AFIAAAPABgACJgBeAAABBwB1ARsAAAATALAARViwBy8bsQccPlmwDNwwMQD//wBQAAAEjAcUAiYAPgAAAQcAogFqAT8AEwCwAEVYsAcvG7EHID5ZsBLcMDEA//8AUgAAA8AF3gImAF4AAAEHAKIBAgAJABMAsABFWLAHLxuxBxw+WbAS3DAxAP//AFAAAASMBzcCJgA+AAABBwCfAJsBNgAJALAHL7AO3DAxAP//AFIAAAPABgECJgBeAAABBgCfMwAACQCwBy+wDtwwMQD////2AAAHVwdCAiYAgQAAAQcAdQK7AUIAEwCwAEVYsAYvG7EGID5ZsBXcMDEA//8ASP/sBoQGAQImAIYAAAEHAHUCcQABAAkAsBcvsD/cMDEA//8Aaf+hBSIHgAImAIMAAAEHAHUB4AGAABMAsABFWLAQLxuxECA+WbAs3DAxAP//AE//dwQ9Bf4CJgCJAAABBwB1ATD//gATALAARViwBC8bsQQcPlmwKNwwMQD///+mAAAEKgSNAiYCMAAAAQcCJv8W/24ARgCyHxcBcbJvFwFxsv8XAXGyDxcBcravF78XzxcDcrL/FwFysl8XAXK2vxfPF98XA3GyPxcBcbTfF+8XAl20HxcvFwJdMDH///+mAAAEKgSNAiYCMAAAAQcCJv8W/24ARgCyHxcBcbJvFwFxsv8XAXGyDxcBcravF78XzxcDcrL/FwFysl8XAXK2vxfPF98XA3GyPxcBcbTfF+8XAl20HxcvFwJdMDH//wAkAAAEFgSNAiYB2AAAAQYCJjK+AAgAsgALAV0wMf//AAkAAASUBh4CJgIzAAABBwBEAMcAHgATALAARViwBC8bsQQePlmwDNwwMQD//wAJAAAElAYeAiYCMwAAAQcAdQFmAB4AEwCwAEVYsAUvG7EFHj5ZsA3cMDEA//8ACQAABJQGHwImAjMAAAEGAJ5nHgATALAARViwBC8bsQQePlmwD9wwMQD//wAJAAAElAYUAiYCMwAAAQYApWkfAAkAsAQvsBbcMDEA//8ACQAABJQF6gImAjMAAAEHAGoAkgAeABYAsABFWLAELxuxBB4+WbAS3LAb0DAx//8ACQAABJQGfAImAjMAAAEHAKMA/ABSABYAsABFWLAELxuxBB4+WbAQ3LAY0DAx//8ACQAABJQGmQImAjMAAAAHAicBAgAE//8AT/5BBEMEnQImAjEAAAAHAHkBawAA//8AdgAAA7UGHgImAigAAAEHAEQAlgAeABMAsABFWLAGLxuxBh4+WbAN3DAxAP//AHYAAAO1Bh4CJgIoAAABBwB1ATUAHgATALAARViwBy8bsQcePlmwDtwwMQD//wB2AAADtQYfAiYCKAAAAQYAnjYeABMAsABFWLAGLxuxBh4+WbAQ3DAxAP//AHYAAAO1BeoCJgIoAAABBgBqYR4AFgCwAEVYsAYvG7EGHj5ZsBPcsBzQMDH///+mAAABfgYeAiYB4wAAAQcARP91AB4AEwCwAEVYsAIvG7ECHj5ZsAXcMDEA//8AgwAAAlsGHgImAeMAAAEGAHUTHgATALAARViwAy8bsQMePlmwBtwwMQD///+pAAACWAYfAiYB4wAAAQcAnv8VAB4AEwCwAEVYsAIvG7ECHj5ZsAjcMDEA////nQAAAmMF6gImAeMAAAEHAGr/QAAeABYAsABFWLACLxuxAh4+WbAL3LAU0DAx//8AdgAABGcGFAImAd4AAAEHAKUAiAAfAAkAsAUvsBXcMDEA//8AT//wBG8GHgImAd0AAAEHAEQA1QAeABMAsABFWLALLxuxCx4+WbAe3DAxAP//AE//8ARvBh4CJgHdAAABBwB1AXQAHgAJALALL7Af3DAxAP//AE//8ARvBh8CJgHdAAABBgCedR4AEwCwAEVYsAsvG7ELHj5ZsCHcMDEA//8AT//wBG8GFAImAd0AAAEGAKV3HwAJALALL7Ao3DAxAP//AE//8ARvBeoCJgHdAAABBwBqAKAAHgAWALAARViwCy8bsQsePlmwJNywLdAwMf//AGf/8AQeBh4CJgHXAAABBwBEALUAHgATALAARViwCC8bsQgePlmwEdwwMQD//wBn//AEHgYeAiYB1wAAAQcAdQFUAB4AEwCwAEVYsA8vG7EPHj5ZsBLcMDEA//8AZ//wBB4GHwImAdcAAAEGAJ5VHgATALAARViwCC8bsQgePlmwFNwwMQD//wBn//AEHgXqAiYB1wAAAQcAagCAAB4AFgCwAEVYsAgvG7EIHj5ZsBfcsCDQMDH//wAFAAAENgYeAiYB0wAAAQcAdQEtAB4AEwCwAEVYsAEvG7EBHj5ZsAvcMDEA//8ACQAABJQFzAImAjMAAAEGAHBiIgATALAARViwBC8bsQQePlmwDNwwMQD//wAJAAAElAYEAiYCMwAAAQcAoQCaAB4AEwCwAEVYsAQvG7EEHj5ZsA7cMDEAAAIACf5SBJQEjQAWABkAc7IZGhsREjmwGRCwFtAAsABFWLAALxuxAB4+WbAARViwFC8bsRQQPlmwAEVYsAEvG7EBED5ZsABFWLAMLxuxDBI+WbEHA7AKK1gh2Bv0WbABELAR0LIXFAAREjmwFy+xEwGwCitYIdgb9FmyGQAUERI5MDEBASMGBhUUMzI3FwYjIiY1NDcnIQcjAQMhAwK/AdU2V0pHLC4VSVxfdJ1Z/h5f9QHXPAFUqgSN+3M4XjFEF44sbluSYev5BI39JQG6AP//AE//8ARDBh4CJgIxAAABBwB1AWMAHgAJALALL7Ae3DAxAP//AE//8ARDBh8CJgIxAAABBgCeZB4AEwCwAEVYsAsvG7ELHj5ZsCDcMDEA//8AT//wBEMF/AImAjEAAAEHAKIBSgAnABMAsABFWLALLxuxCx4+WbAk3DAxAP//AE//8ARDBh8CJgIxAAABBgCfex4ACQCwCy+wINwwMQD//wBqAAAEKgYfAiYCMAAAAQYAn/geAAkAsAEvsBjcMDEA//8AdgAAA7UFzAImAigAAAEGAHAxIgATALAARViwBi8bsQYePlmwDdwwMQD//wB2AAADtQYEAiYCKAAAAQYAoWkeABMAsABFWLAGLxuxBh4+WbAP3DAxAP//AHYAAAO1BfwCJgIoAAABBwCiARwAJwATALAARViwBi8bsQYePlmwFNwwMQAAAQB2/lIDtQSNABsAhLIRHB0REjkAsABFWLAWLxuxFh4+WbAARViwDy8bsQ8SPlmwAEVYsAQvG7EEED5ZsABFWLAULxuxFBA+WbIbFgQREjmwGy+xAAGwCitYIdgb9FmwFBCxAgGwCitYIdgb9FmwA9CwDxCxCgOwCitYIdgb9FmwFhCxGAGwCitYIdgb9FkwMQEhESEVIwYGFRQzMjcXBiMiJjU0NyERIRUhESEDX/4KAkxeV0pHLC4VSVxfdIf9+wM8/bcB9gH4/srCOF4xRBeOLG5bhl8EjcT+8gD//wB2AAADtQYfAiYCKAAAAQYAn00eABMAsABFWLAGLxuxBh4+WbAR3DAxAP//AFT/8ARIBh8CJgHlAAABBgCeaB4AEwCwAEVYsAovG7EKHj5ZsCHcMDEA//8AVP/wBEgGBAImAeUAAAEHAKEAmwAeABMAsABFWLAKLxuxCh4+WbAg3DAxAP//AFT/8ARIBfwCJgHlAAABBwCiAU4AJwATALAARViwCi8bsQoePlmwJdwwMQD//wBU/fkESASdAiYB5QAAAAcBugFq/pL//wB2AAAEaAYfAiYB5AAAAQYAnnseABMAsABFWLAHLxuxBx4+WbAQ3DAxAP///5EAAAJuBhQCJgHjAAABBwCl/xcAHwAJALACL7AP3DAxAP///6sAAAJaBcwCJgHjAAABBwBw/xAAIgATALAARViwAi8bsQIePlmwBdwwMQD///+9AAACQwYEAiYB4wAAAQcAof9IAB4AEwCwAEVYsAIvG7ECHj5ZsAfcMDEA//8AFf5SAY0EjQImAeMAAAAGAKTsAP//AHwAAAGCBfwCJgHjAAABBgCi+ycAEwCwAEVYsAIvG7ECHj5ZsAzcMDEA//8AJP/wBDcGHwImAeIAAAEHAJ4A9AAeABMAsABFWLAALxuxAB4+WbAT3DAxAP//AHb+AARoBI0CJgHhAAAABwG6ARL+mf//AHYAAAOUBh4CJgHgAAABBgB1Ch4AEwCwAEVYsAUvG7EFHj5ZsAjcMDEA//8Adv4BA5QEjQImAeAAAAAHAboBEP6a//8AdgAAA5QEkAImAeAAAAEHAboBlQOKABAAsABFWLAKLxuxCh4+WTAx//8AdgAAA5QEjQImAeAAAAAHAKIBcv1G//8AdgAABGcGHgImAd4AAAEHAHUBhQAeABMAsABFWLAILxuxCB4+WbAM3DAxAP//AHb9+QRnBI0CJgHeAAAABwG6AXj+kv//AHYAAARnBh8CJgHeAAABBwCfAJ0AHgATALAARViwBi8bsQYePlmwD9wwMQD//wBP//AEbwXMAiYB3QAAAQYAcHAiAAkAsAsvsB3cMDEA//8AT//wBG8GBAImAd0AAAEHAKEAqAAeABMAsABFWLALLxuxCx4+WbAg3DAxAP//AE//8ARvBh0CJgHdAAABBwCmAP4AHgAMALALL7Af3LAh0DAx//8AdgAABDkGHgImAdoAAAEHAHUBFwAeAAkAsAQvsBncMDEA//8Adv4BBDkEjQImAdoAAAAHAboBGP6a//8AdgAABDkGHwImAdoAAAEGAJ8vHgAJALAEL7Ab3DAxAP//AD7/8APvBh4CJgHZAAABBwB1AUEAHgAJALAJL7Ao3DAxAP//AD7/8APvBh8CJgHZAAABBgCeQh4AEwCwAEVYsAkvG7EJHj5ZsCrcMDEA//8APv5BA+8EnQImAdkAAAAHAHkBTwAA//8APv/wA+8GHwImAdkAAAEGAJ9ZHgAJALAJL7Aq3DAxAP//ACT9/wQWBI0CJgHYAAAABwG6ASX+mP//ACQAAAQWBh8CJgHYAAABBgCfRx4AEwCwAEVYsAYvG7EGHj5ZsA3cMDEA//8AJP5HBBYEjQImAdgAAAAHAHkBOQAG//8AZ//wBB4GFAImAdcAAAEGAKVXHwATALAARViwDy8bsQ8ePlmwE9wwMQD//wBn//AEHgXMAiYB1wAAAQYAcFAiAAkAsAAvsBDcMDEA//8AZ//wBB4GBAImAdcAAAEHAKEAiAAeABMAsABFWLAILxuxCB4+WbAT3DAxAP//AGf/8AQeBnwCJgHXAAABBwCjAOoAUgAMALAAL7AV3LAa0DAx//8AZ//wBDQGHQImAdcAAAEHAKYA3gAeAAwAsAAvsBLcsBTQMDEAAQBn/oIEHgSNAB4AY7IbHyAREjkAsABFWLAXLxuxFx4+WbAARViwAC8bsQAePlmwAEVYsA0vG7ENGD5ZsABFWLASLxuxEhA+WbIEEgAREjmwDRCxCAOwCitYIdgb9FmwEhCxGwGwCitYIdgb9FkwMQERBgYHBhUUMzI3FwYjIiY1NDcmJicRMxEUFjMyNxEEHgF9d39HLC4VSVxfdEDN8gLxfmzlBASN/PyBvTJWWkQXjixuW11JBta7AwX9AHNo1AMH//8AKAAABeUGHwImAdUAAAEHAJ4BGQAeABMAsABFWLABLxuxAR4+WbAP3DAxAP//AAUAAAQ2Bh8CJgHTAAABBgCeLh4AEwCwAEVYsAgvG7EIHj5ZsA3cMDEA//8ABQAABDYF6gImAdMAAAEGAGpZHgAWALAARViwCC8bsQgePlmwENywGdAwMf//AEEAAAPzBh4CJgHSAAABBwB1ATAAHgATALAARViwCC8bsQgePlmwDNwwMQD//wBBAAAD8wX8AiYB0gAAAQcAogEXACcAEwCwAEVYsAcvG7EHHj5ZsBLcMDEA//8AQQAAA/MGHwImAdIAAAEGAJ9IHgATALAARViwBy8bsQcePlmwD9wwMQD//wASAAAFQgZBAiYAJQAAAAYArr8A///+5wAABEwGQQImACkAAAAHAK7+IQAA///+8AAABRgGQQImACwAAAAHAK7+KgAA///+8wAAAZ8GQwImAC0AAAAHAK7+LQAC////p//sBTIGQQAmADMUAAAHAK7+4QAA///+4QAABToGQQAmAD1kAAAHAK7+GwAA////sgAABPEGQQAmALoUAAAHAK7+7AAA////h//0AtoGmgImAMMAAAEHAK//IP/rABwAsABFWLAMLxuxDBw+WbAY3LAQ0LAYELAh0DAx//8AEgAABUIFsAIGACUAAP//AJQAAASjBbACBgAmAAD//wCUAAAETAWwAgYAKQAA//8AUAAABIwFsAIGAD4AAP//AJQAAAUYBbACBgAsAAD//wCjAAABnwWwAgYALQAA//8AlAAABRgFsAIGAC8AAP//AJQAAAZqBbACBgAxAAD//wCUAAAFFwWwAgYAMgAA//8AZv/sBR4FxAIGADMAAP//AJQAAATUBbACBgA0AAD//wAtAAAEsAWwAgYAOAAA//8ABwAABNYFsAIGAD0AAP//ACkAAATpBbACBgA8AAD///+/AAAChQcJAiYALQAAAQcAav9iAT0AFgCwAEVYsAIvG7ECID5ZsAvcsBTQMDH//wAHAAAE1gcCAiYAPQAAAQcAagCzATYAFgCwAEVYsAgvG7EIID5ZsBDcsBnQMDH//wBW/+sEeQZBAiYAuwAAAQcArgFQAAAACQCwEy+wJNwwMQD//wBg/+wEDAZBAiYAvwAAAQcArgEZAAAACQCwCS+wKtwwMQD//wB+/mEEBgZBAiYAwQAAAQcArgEjAAAACQCwAy+wFNwwMQD//wCp//QCYQYsAiYAwwAAAQYArg/rAAkAsAAvsA/cMDEA//8AgP/rBAgGogImAMsAAAEGAK8d8wAcALAARViwAC8bsQAcPlmwHtywFdCwHhCwJ9AwMf//AI4AAARrBDoCBgCOAAD//wBP/+wEPQROAgYAUwAA//8Akv5gBB8EOgIGAHYAAP//ABYAAAPaBDoCBgBaAAAAAQA+/kkEZQRKABwAarITHR4REjkAsABFWLAALxuxABw+WbAARViwBS8bsQUcPlmwAEVYsA8vG7EPEj5ZsABFWLAULxuxFBI+WbIEAA8REjmwDxCxCwGwCitYIdgb9FmyEwAPERI5sAAQsRkBsAor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BYYAYAT+AJQE1ABKBNsALQU3AH0FLQASBwoAMAUQACkE4AAHBNEAUAIxAIQDWAAUAjEADANrADUDnAADApQAMQRUAFoEgQB8BDAATwSEAE8ESwBTAtYALQSJAFIEcQB5AgsAfQIB/7UELQB9AgsAjAb2AHwEcwB5BI4ATwSBAHwEiwBPAtAAfAQhAEsCqQAIBHIAdwP1ABYF8gAhBAYAHwPlAAwEBgBSAq8AOAICAK4CrwAbBVEAdQIeAIYEfQBkBLUAXgWdAF0EQAALAfwAiAT4AFoDhQBdBkQAVwORAI0D4gBXBG0AfwZEAFcD2wCbAwoAfwRKAF8C9gA8AvYANwKbAHAEuwCSA+0ARQJCAI4CEABtAvYAgAOnAHcD4gBdBdAAWQYrAFAGVwBnA+QAQgeF//YERABNBYQAaQTKAJQE5wCIBsEASASnAGcEkQBDBIgATwSXAIIE7QBPBbAAHwIaAI8EmACOBGQAIgJPACEFkwCQBIgAfge0AGQHOgBbAgwAiwWIAFEC0P/kBYoAWASeAE8FpAB9BPIAdwIm/7UEPABZA+YAlAOwAHID3ACbA3wAdQILAIECsgB4Ak0AKQPYAHoDHwBJAmwAggAA/I4AAP1eAAD8cwAA/T4AAPwMAAD9HAJdAMYEPABnAkIAjgR1AJsFvwAZBXoAWwU4ACAEkABsBbEAmwSQAEcF7wBKBaoARAVbAGsEhABWBMYAlgQOACAEiABUBGAAYAQaAGEEiAB+BKEAcwKqAKkEagAWBBMAZATzAC0EiACABDcAUgSQAFIELQA/BGAAgAXQAEQFyQBPBpQAZgSzAHYEe//hBnEAMwX+ACIFWQBoCIgALQiPAJsGWwAxBaoAkgUIAJAGBgAkB6IAFgTWAEkFqACUBakALQUKADkGXwBPBfkAkgWJAI4HmwCYB/kAmAYaABgG+QCbBQcAkAVQAGsHVACgBPcAIAR9AFsEjwCPA1oAhQT2ACcGdgAeBBYATQSYAIYEbgCPBJoAIQYDAI8ElwCGBJgAhgP1ACMF0wBUBNMAhgRmAF8GjgCGBuwAfgUXAB8GbwCPBGgAjwQ8AFEGhACRBHAAJwRx/9sEPABUBtEAHgbkAIYEif/uBJgAhgdJAIgGTwBwBGf/4AcoAJgGAQCGBQwAHARgAAoHQgCsBjYAnQbtAIAF5gCCCTIAowf5AI8EIAAoA/AAMwV6AF8EiABPBRoAEAQOACAFegBfBIgATwdFAIgGRAB0B0kAiAZPAHAFGgBmBEoAXAT/AG0AAPxmAAD8cwAA/XsAAP2lAAD6JAAA+k0GKgCUBRsAhgRn/+AFEwCUBIYAfARqAI8DoQB+BPIAmwQgAH4IHAAWBtMAHgXMAJsE+gCPBSwAkASrAI4GlQA0BaQAPQYoAJQFDQCGB9AAlAWqAH4IRwCbBvUAfgYqAGcE/wBhBTkAKQRGAB8HMQAtBXAAJgX6AI4E3ABfBXQAgARzAHQFhgCEBiQAFgTD/8sFIQCQBHgAjgYoAC0FHQAhBa8AmwSIAH4GNQCUBRoAhgd+AJQGeACPBYgAUQSmAFsEpgBdBMcANAOvAC0FZwApBHQAHwUHAFIG8QBoBt0AXgZTADwFKAAvBHsASAQ+AHQHvgBCBp0AQAf9AJQGngB3BQQAXQQsAFUFqgAhBR0ARAVVAIEGSQAtBT4AIQMsAGcEFAAACCkAAAQUAAAIKQAAArkAAAIKAAABXAAABH8AAAIwAAABogAAAQAAAADRAAAAAAAAAqEARwKhAEcFKQCdBjAAgQOcAAMBwABjAbwAMwHOADIBqABKAxQAbAMbAEADCAAyBF0AQASZAFwCywCIA/oAigWmAIoByABaB6cASgJyAGwCaQBUA5wALQL2ADUDXABpBLUAXwZwACEGuACYCJMAlAYoACEGjAB8BIwAXgX1ACEENAAoBKIAIQVeAE8FfQAoBeQAcAPiAEwILgCQBQkAbQUUAJYGNQBZBt0AVAbRAFsGogBYBJEAYgWWAKYE2QBABIMAngSyADsIRQBeAi3/rwSOAGUEegCRBBEAPAQqAIAEDAAkAlsAoQKYAGMB8QBFBRsALQSoABgEvAAtByMALQcjAC0FEQAtBrcASwAAAAAIMABZCDUAXAL2ADwC9gCAAvYASwQdAE8EHQBYBB0AOQQcAGAEHQBnBB0AMAQdAD4EHQBCBB0AlgQdAFkEKgBBBDwABQReABUGBwAoBHsACQSEAGcEOwAkBDQAPgRcAHYEwABMBG0AdgTAAE8E3QB2BgYAdgO5AHYEWwB2A9UAJAH8AIUE3gB2BKYAVAPFAHYENAA+BGYAOAOkAAkDuQB2BHsACQTAAE8EewAJA5gAQgTYAHYEGQBEBZ0AUAVUAFAE5ABfBZEAJASAAE8HVAAkB1cAdgWXACQE1wB2BHEAdgVZACcGOgAaBEYAQgTkAHYEXAB2BMsAJARGAB8FXQB2BIwAQQaEAHYHCgB2BVoACgYgAHYEZwB2BIAAPAaSAHYEiABDBCIACgaSABoEnQB2BRoAdgVuACQF8ABPBFoABQTEABUGlQAkBIwAQQSMAHYF/gAKBNIATwRGAEIEwABPBGYAOAP3AEYINgB2BOsAKAL2ADcC9gA1AvYATwL2AE0C9gA2AvYASwL2AEYDuQCQArIAlgPgAHYEOwAKBLsAVgVEAJsFKACbBDAAgQU5AJsELQCBBHoAdgSAAE8EYAB2BJ4ACQIFAJQDoQB1AAD8nQQLAHoEC/9MBAsAdQQLAHUDuQB2A6EAdQOhAHUC9gBLAvYANQL2AE8C9gBNAvYANgL2AEsC9gBGBXoAawWiAGsFhgCbBeAAawXiAGsEGwCXBIIAbgRXAA8EvgA1BGsAZgQuAEMDoQB1AbMAXAaYAE8EtABzAhD/sASMADkEjABqBIwALASMAGYEjABjBIwANQSMAG8EjABZBIwAaASMAOMCJv+1Aib/tQIbAI8CG//7AhsAjwRgAHYE6wBiBDMAOgSIAHwEPQBQBJgATwSTAE8EoQBMBJQAfASfAE8ESwBTBIkAUQOkAFsFAwBdA8QAAwZG//EECQB2BMAATwUJADEE3QB2Af4AAAKgAEcFWP/3BVj/9wSP/9QE2wAtAqn/6AVTABIFUwASBVMAEgVTABIFUwASBVMAEgVTABIFOQBmBIYAlASGAJQEhgCUBIYAlAJC/8gCQgCjAkL/ywJC/78FrgCUBYYAZgWGAGYFhgBmBYYAZgWGAGYFNwB9BTcAfQU3AH0FNwB9BOAABwRUAFoEVABaBFQAWgRUAFoEVABaBFQAWgRUAFoEMABPBEsAUwRLAFMESwBTBEsAUwIa/7QCGgCPAhr/twIa/6sEcwB5BI4ATwSOAE8EjgBPBI4ATwSOAE8EcgB3BHIAdwRyAHcEcgB3A+UADAPlAAwFUwASBFQAWgVTABIEVABaBVMAEgRUAFoFOQBmBDAATwU5AGYEMABPBTkAZgQwAE8FOQBmBDAATwU6AJQFGgBPBIYAlARLAFMEhgCUBEsAUwSGAJQESwBTBIYAlARLAFMEhgCUBEsAUwVyAGoEiQBSBXIAagSJAFIFcgBqBIkAUgVyAGoEiQBSBa8AlARxAHkCQv+zAhr/nwJC/80CGv+5AkL/3wIa/8sCQgAXAgsAAAJCAJ0GswCjBAwAfQRxAC0CJv+1BQsAlAQtAH0EVACUAgsAigRUAJQCCwBVBFQAlAKhAIwEVACUAucAjAWuAJQEcwB5Ba4AlARzAHkFrgCUBHMAeQRz/6UFhgBmBI4ATwWGAGYEjgBPBYYAZgSOAE8E/gCUAtAAfAT+AJQC0ABPBP4AlALQADgE1ABKBCEASwTUAEoEIQBLBNQASgQhAEsE1ABKBCEASwTUAEoEIQBLBNsALQKpAAgE2wAtAqkACATbAC0C0QAIBTcAfQRyAHcFNwB9BHIAdwU3AH0EcgB3BTcAfQRyAHcFNwB9BHIAdwU3AH0EcgB3BwoAMAXyACEE4AAHA+UADATgAAcE0QBQBAYAUgTRAFAEBgBSBNEAUAQGAFIHhf/2BsEASAWEAGkEiABPBHr/pgR6/6YEOwAkBJ4ACQSeAAkEngAJBJ4ACQSeAAkEngAJBJ4ACQSAAE8D4AB2A+AAdgPgAHYD4AB2Afz/pgH8AIMB/P+pAfz/nQTdAHYEwABPBMAATwTAAE8EwABPBMAATwSEAGcEhABnBIQAZwSEAGcEPAAFBJ4ACQSeAAkEngAJBIAATwSAAE8EgABPBIAATwR6AGoD4AB2A+AAdgPgAHYD4AB2A+AAdgSmAFQEpgBUBKYAVASmAFQE3gB2Afz/kQH8/6sB/P+9AfwAFQH8AHwD1QAkBFsAdgO5AHYDuQB2A7kAdgO5AHYE3QB2BN0AdgTdAHYEwABPBMAATwTAAE8EXAB2BFwAdgRcAHYENAA+BDQAPgQ0AD4ENAA+BDsAJAQ7ACQEOwAkBIQAZwSEAGcEhABnBIQAZwSEAGcEhABnBgcAKAQ8AAUEPAAFBCoAQQQqAEEEKgBBBVMAEgSG/ucFr/7wAkL+8wWa/6cFRP7hBW//sgKq/4cFUwASBQwAlASGAJQE0QBQBa8AlAJCAKMFCwCUBwEAlAWuAJQFhgBmBR0AlATbAC0E4AAHBRAAKQJC/78E4AAHBIQAVgRgAGAEiAB+AqoAqQRgAIAEmACOBI4ATwS7AJID9QAWBAYAHwKq/8wEYACABI4ATwRgAIAGlABmBIYAlAR1AJsE1ABKAkIAowJC/78EcQAtBSgAmwULAJQFCgA5BVMAEgUMAJQEdQCbBIYAlAWoAJQHAQCUBa8AlAWGAGYFsQCbBR0AlAU5AGYE2wAtBRAAKQRUAFoESwBTBJgAhgSOAE8EgQB8BDAATwPlAAwEBgAfBEsAUwNaAIUEIQBLAgsAfQIa/6sCAf+1BG4AjwPlAAwHCgAwBfIAIQcKADAF8gAhBwoAMAXyACEE4AAHA+UADAFaAFICmABlBEoAjwIm/7EBvAAzBwEAlAb2AHwFUwASBFQAWgSGAJQFqACUBEsAUwSYAIYFqgBEBckATwUaABAEDv/xCHMATwlrAGYE1gBJBBYATQU5AGYEMABPBOAABwQOACACQgCjB6IAFgZ2AB4CQgCjBVMAEgRUAFoFUwASBFQAWgeF//YGwQBIBIYAlARLAFMFiABRBDwAWQQ8AFkHogAWBnYAHgTWAEkEFgBNBagAlASYAIYFqACUBJgAhgWGAGYEjgBPBXoAXwSIAE8FegBfBIgATwVQAGsEPABRBQoAOQPlAAwFCgA5A+UADAUKADkD5QAMBYkAjgRmAF8G+QCbBm8AjwSEAE8FUwASBFQAWgVTABIEVABaBVMAEgRUAFoFUwAQBFT/mgVTABIEVABaBVMAEgRUAFoFUwASBFQAWgVTABIEVABaBVMAEgRUAFoFUwASBFQAWgVTABIEVABaBVMAEgRUAFoEhgCUBEsAUwSGAJQESwBTBIYAlARLAFMEhgCUBEsAUwSG/9UES/+OBIYAlARLAFMEhgCUBEsAUwSGAJQESwBTAkIAowIaAI8CQgCUAgsAeAWGAGYEjgBPBYYAZgSOAE8FhgBmBI4ATwWGACcEjv+jBYYAZgSOAE8FhgBmBI4ATwWGAGYEjgBPBYoAWASeAE8FigBYBJ4ATwWKAFgEngBPBYoAWASeAE8FigBYBJ4ATwU3AH0EcgB3BTcAfQRyAHcFpAB9BPIAdwWkAH0E8gB3BaQAfQTyAHcFpAB9BPIAdwWkAH0E8gB3BOAABwPlAAwE4AAHA+UADATgAAcD5QAMBKIATwTbAC0D9QAjBYkAjgRmAF8EdQCbA1oAhQYkABYEw//LBHEAeQUH/9AFB//QBHX/8ANa/+IFPP/jBET/rgTgAAcEDgAgBRAAKQQGAB8EYABgBGUAAgYwAIEEjABRBIwATwSMADQEjACBBKAAiQS0AHwEoABdBLQAfQVyAGoEiQBSBa4AlARzAHkFUwASBFQADQSGAEgESwABAkL+9gIa/uIFhgBmBI4AFgT+ADIC0P9uBTcAcQRyAA8E3/6sBQwAlASBAHwFOgCUBIQATwU6AJQEhABPBa8AlARxAHkFCwCUBC0AfQULAJQELQB9BFQAlAILAHgHAQCUBvYAfAWuAJQEcwB5BYYAZgUdAJQEgQB8BP4AlALQAHIE1ABKBCEASwTbAC0CqQAIBTcAfQUtABID9QAWBS0AEgP1ABYHCgAwBfIAIQTRAFAEBgBSBcz+HASeAAkEHP8qBRr/NwI4/zkEyv+TBHj+6ATu/6QEngAJBGAAdgPgAHYEKgBBBN4AdgH8AIUEWwB2BgYAdgTdAHYEwABPBG0AdgQ7ACQEPAAFBF4AFQH8/50EPAAFA+AAdgO5AHYENAA+AfwAhQH8/50D1QAkBFsAdgRGAB8EngAJBGAAdgO5AHYD4AB2BOQAdgYGAHYE3gB2BMAATwTYAHYEbQB2BIAATwQ7ACQEXgAVBEYAQgTeAHYEgABPBDwABQX+AAoE5AB2BEYAHwWdAFAF0QCFBkb/8QTAAE8ENAA+BgcAKAYHACgGBwAoBDwABQVTABIEVABaBIYAlARLAFMEngAJA+AAdgIaAHgAAQAAB2z+DAAACWv6JP5BCVwAAQAAAAAAAAAAAAAAAAAABQ4AAwSYAfQABQAABZoFMwAAAR8FmgUzAAAD0QBmAgAAAAIAAAAAAAAAAADgAAL/UAAgWwAAACAAAAAAR09PRwBAAAD//QYA/gAAZgeaAgAgAAGfAAAAAAQ6BbAAIAAgAAMAAAABAAAFEAkLBAAAAgICAwYFBwYCAwMEBQIDAwQFBQUFBQUFBQUFAgIFBQUECAYGBgYFBQYGAwUGBQgGBgYGBgUFBgYIBgUFAgQCBAQDBQUFBQUDBQUCAgUCCAUFBQUDBQMFBAcFBAUDAgMGAgUFBgUCBgQHBAQFBwQDBQMDAwUEAwIDBAQHBwcECAUGBQYIBQUFBQYGAgUFAwYFCQgCBgMGBQYGAgUEBAQEAgMDBAQDAAAAAAAAAwUDBQYGBgUGBQcGBgUFBQUFBQUFAwUFBgUFBQUFBwcHBQUHBwYKCgcGBgcJBQYGBgcHBgkJBwgGBggGBQUEBgcFBQUFBwUFBAcFBQcIBgcFBQcFBQUICAUFCAcFCAcGBQgHCAcKCQUEBgUGBQYFCAcIBwYFBgAAAAAAAAcGBQYFBQQGBQkIBwYGBQcGBwYJBgkIBwYGBQgGBwUGBQYHBQYFBwYGBQcGCAcGBQUFBAYFBggIBwYFBQkHCQcGBQYGBgcGBAUJBQkDAgIFAgIBAQADAwYHBAICAgIDBAMFBQMEBgIJAwMEAwQFBwgKBwcFBwUFBgYHBAkGBgcICAcFBgUFBQkCBQUFBQUDAwIGBQUICAYIAAkJAwMDBQUFBQUFBQUFBQUFBQcFBQUFBQUFBQUHBAUEAgUFBAUFBAQFBQUEBQUGBgYGBQgIBgUFBgcFBgUFBQYFBwgGBwUFBwUFBwUGBgcFBQcFBQcFBQUFBAkGAwMDAwMDAwQDBAUFBgYFBgUFBQUFAgQABQUFBQQEBAMDAwMDAwMGBgYHBwUFBQUFBQQCBwUCBQUFBQUFBQUFBQICAgICBQYFBQUFBQUFBQUFBAYEBwUFBgUCAwYGBQUDBgYGBgYGBgYFBQUFAwMDAwYGBgYGBgYGBgYFBQUFBQUFBQUFBQUFAgICAgUFBQUFBQUFBQUEBAYFBgUGBQYFBgUGBQYFBgYFBQUFBQUFBQUFBgUGBQYFBgUGBQMCAwIDAgMCAwgFBQIGBQUCBQIFAwUDBgUGBQYFBQYFBgUGBQYDBgMGAwUFBQUFBQUFBQUFAwUDBQMGBQYFBgUGBQYFBgUIBwUEBQUFBQUFBQgIBgUFBQUFBQUFBQUFBQQEBAQCAgICBQUFBQUFBQUFBQUFBQUFBQUFBQQEBAQEBQUFBQUCAgICAgQFBAQEBAUFBQUFBQUFBQUFBQUFBQUFBQUFBQUHBQUFBQUGBQYDBgYGAwYGBQUGAwYIBgYGBQUGAwUFBQUDBQUFBQQFAwUFBQcFBQUDAwUGBgYGBgUFBggGBgYGBgUGBQUFBQUFBAUFBAUCAgIFBAgHCAcIBwUEAgMFAgIICAYFBQYFBQYHBgUKCwUFBgUFBQMJBwMGBQYFCAgFBQYFBQkHBQUGBQYFBgUGBQYFBgUGBAYEBgQGBQgHBQYFBgUGBQYFBgUGBQYFBgUGBQYFBgUGBQUFBQUFBQUFBQUFBQUFBQUDAgMCBgUGBQYFBgUGBQYFBgUGBQYFBgUGBQYFBgUGBQYGBgYGBgYGBgYFBAUEBQQFBQQGBQUEBwUFBgYFBAYFBQUGBQUFBwUFBQUFBQUFBgUGBQYFBQUDAgYFBgMGBQUGBQYF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AC4AbwByAGcALwBsAGkAYwBlAG4AcwBlAHMALwBMAEkAQwBFAE4AUwBFAC0AMgAuADAAUgBvAGIAbwB0AG8ATQBlAGQAaQB1AG0AAAADAAAAAAAA/2oAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAgAIAAL//wAPAAEAAgAOAAAAAAAAAigAAgBZACUAPgABAEUAXgABAHkAeQABAIEAgQABAIMAgwABAIYAhgABAIkAiQABAIsAlgABAJgAnQABAKQApAABAKgArQADALEAsQABALoAuwABAL8AvwABAMEAwQABAMMAwwABAMcAxwABAMsAywABAM0AzgABANAA0QABANMA0wABANoA3gABAOEA4QABAOUA5QABAOcA6QABAOsA+wABAP0A/QABAP8BAQABAQMBAwABAQgBCQABARYBGgABARwBHAABASABIgABASQBJQADASoBKwABATMBNAABATYBNgABATsBPAABAUEBRAABAUcBSAABAUsBTQABAVEBUQABAVQBWAABAV0BXgABAWIBYgABAWQBZAABAWgBaAABAWoBbAABAW4BbgABAXABcAABAboBugADAbsBwQACAdIB5gABAeoB6gABAfMB8wABAfUB9QABAfwB/gABAgACAQABAgMCAwABAgcCBwABAgkCCwABAhECEQABAhYCGAABAhoCGgABAigCKAABAisCKwABAi0CLQABAjACMwABAl8CYwABAnoC4gABAuUDiwABA40DpAABA6YDsgABA7QDvQABA78D2gABA94D3gABA+AD5wABA+kD6wABA+4D8gABA/QEfAABBH8EfwABBIIEgwABBIUEhgABBIgEiwABBJUE0AABBNIE8QABBPME+gABBPwE/QABBQcFDQABAAEAAgAAAAwAAAAsAAEADgCoAKgAqQCpAKoAqgCrAKsArACsASQBJQEmAScAAQAFAHkApACtAK0BugAAAAEAAAAKADIATAAEREZMVAAaY3lybAAaZ3JlawAabGF0bgAaAAQAAAAA//8AAgAAAAEAAmNwc3AADmtlcm4AFAAAAAEAAAAAAAEAAQACAAYCEAABAAAAAQAIAAEACgAFACQASAABAPoACAAKABQAFQAWABcAGAAZABoAGwAcAB0AJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQA+AGUAZwCBAIMAhACMAI8AkQCTALEAsgCzALQAtQC2ALcAuAC5ALoA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkBLwEzATUBNwE5ATsBQQFDAUUBSQFLAUwBWAFZAZcBnQGiAaUCegJ7An0CfwKAAoECggKDAoQChQKGAocCiAKJAooCiwKMAo0CjgKPApACkQKSApMClAKVApYClwKYApkCtgK4AroCvAK+AsACwgLEAsYCyALKAswCzgLQAtIC1ALWAtgC2gLcAt4C4ALiAuMC5QLnAukC6wLtAu8C8QLzAvUC+AL6AvwC/gMAAwIDBAMGAwgDCgMMAw4DEAMSAxQDFgMYAxoDHAMeAyADIgMkAyUDJwMpAysDLQOGA4cDiAOJA4oDiwOMA44DjwOQA5EDkgOTA5QDlQOWA5cDmAOZA5oDmwOcA50DrQOuA68DsAOxA7IDswO0A7UDtgO3A7gDuQO6A7sDvAO9A74DvwPAA8EDwgPTA9UD1wPZA+4D8APyBAcEDQQTBH0EggSGBQcFCQACAAAAAgAKQXoAAQPuAAQAAAHyB9A8GDwYB/4IYD5QPwg8HkEuPtQIZj92P3Y/Ej9gP3Y/dkEuP6IMBAzSP+xAvkD2PDA92kEUDUg+sj/APNoNjg7EDs4/mD+YPuI/wD/aD9BA3BA2PIpA3BBQP8BBLhCWPRg+UEEuPlARGBIWExgT+hScQNwUoj+YF4gZehqYGrIauBq+Hbgdvh34Hi4euCBCIgwj4j92JTAm2jwwKTw/dj92PJA/dj92P3YqEivAP3Y87iyqLXAuAi5kL0o85C/cPIowsjDcMrY/wDZANn43vDmKP8A4RjjUOP45VDmKPlA+4kC+QNw5sD/APRg85DwwPIo/Ej8SPxI/djwwPIo/dj92QS485DwwPIo8GDnaPBg8GDwYQWo7ZDuyQWQ8DkFMQVJBZEFSQUxBTEFMQUw8AEFSPB5BLkEuQS5BLj/sPlA+UD5QPlA+UD5QPlA8Hj7UPtQ+1D7UP3Y/dj92P3Y/dkEuQS5BLkEuQS492j6yPrI+sj6yPrI+sj6yPNo82jzaPNo/mD7iPuI+4j7iPuJA3EDcPlA+sj5QPrI+UD6yPB48HjwePB5BLj7UPNo+1DzaPtQ82j7UPNo+1DzaP3Y/mD92P3Y/dj92P3Y/Ej9gP2A/YD9gP3Y/mD92P5g/dj+YP5hBLj7iQS4+4kEuPuI/2j/aP9o/7D/sP+xA9j3aQNw92kEUQRRBFEFkQWRBakFSQVJBUkFSQVJBUkFSQWRBZEFkQWRBZEFSQVJBUkFkQUw8DjwOPA48DkFkQWRBZEFqPlA+1D92P3ZBLj3aPlA/CD7UQRQ/dj92PxI/dj92QS4/oj/sPdo8MD92Pdo/mD7iQNw+4j7UPRg/dj92PxI/EjyQPlA/CD0YPtQ/dj92QS4/ojweP+w8MD6yPNo+4j/AQNw8ijzaPORA3ED2QPZA9j3aQNw8GDwYPBg/dj+YPlA+sj7UPNpAvkDcPB492kDcP3Y8MDyKP3Y+UD6yPlA+sj7UPNo82jzaPDA8ikEuPuI+4j/APJBA3DyQQNw8kEDcPlA+sj5QPrI+UD6yPlA+sj5QPrI+UD6yPlA+sj5QPrI+UD6yPlA+sj5QPrI+UD6yPtQ82j7UPNo+1DzaPtQ82j7UPNo+1DzaPtQ82j7UPNo/dj92QS4+4kEuPuJBLj7iQS4+4kEuPuJBLj7iQS4+4j7iPdpA3D3aQNw92kDcP+w9GDzkP5g87j0YPxI92j92P5g+UD6yPtQ/dkEuPuI/2j8IP8BBLkEuP3Y/mD8SPxI/YD92P5g/dj+YQS4/oj/AP9o/7EC+QNxAvkDcQPZBFEEuQVJBZEFSQUxBakFMQVJBZEFqAAIApQAEAAQAAAAGAAYAAQALAAwAAgATABMABAAlACoABQAsAC0ACwAvADYADQA4ADgAFQA6AD8AFgBFAEYAHABJAEoAHgBMAEwAIABPAE8AIQBRAFQAIgBWAFYAJgBYAFgAJwBaAF0AKABfAF8ALACKAIoALQCWAJYALgCdAJ0ALwCxALUAMAC3ALkANQC7ALsAOAC9AL0AOQDAAMEAOgDDAMMAPADFAMUAPQDHAM4APgDSANIARgDUAN4ARwDgAO8AUgDxAPEAYgD2APgAYwD7APwAZgD+AQAAaAEDAQUAawEKAQoAbgENAQ0AbwEYARoAcAEiASIAcwEuATAAdAEzATUAdwE3ATcAegE5ATkAewE7ATsAfAFDAUQAfQFUAVQAfwFWAVYAgAFYAVgAgQFcAV4AggGEAYUAhQGHAYkAhwHYAdgAigHaAdsAiwHdAd0AjQHgAeEAjgHrAe0AkAH/Af8AkwIOAhAAlAIwAjAAlwIzAjMAmAJFAkUAmQJHAkgAmgJ6AnsAnAJ9An0AngJ/ApQAnwKZAqAAtQKiAqUAvQKqAq8AwQK0ArwAxwK+Ar4A0ALAAsAA0QLCAsIA0gLEAsQA0wLGAs8A1ALYAtoA3gLcAtwA4QLeAt4A4gLgAuAA4wLiAuIA5ALnAucA5QLpAukA5gLrAusA5wLtAu0A6ALvAu8A6QLxAv0A6gL/Av8A9wMBAwEA+AMDAwMA+QMOAw4A+gMQAxAA+wMSAxIA/AMgAyAA/QMiAyUA/gMnAycBAgMpAykBAwMvAzgBBANDA0cBDgNNA08BEwNUA1QBFgNlA2kBFwNtA28BHAN4A3gBHwOGA4sBIAOOA50BJgOgA6ABNgOkA6QBNwOmA6YBOAOqA6oBOQOtA64BOgOwA7EBPAOzA7kBPgO7A70BRQO/A8QBSAPGA8cBTgPJA8wBUAPSA9MBVAPVA9UBVgPXA9cBVwPZA9wBWAPfA+QBXAPmA+YBYgPqA+sBYwPwA/ABZQPyA/sBZgP+A/8BcAQBBAQBcgQLBAwBdgQQBBABeAQSBBgBeQQeBEYBgARIBEgBqQRKBFcBqgRfBF8BuARwBHUBuQR3BHcBvwR7BHwBwAR/BH8BwgSBBIIBwwSEBIQBxQSGBIYBxgSXBJsBxwSdBJ0BzASfBKABzQSiBKIBzwSmBKgB0ASqBKoB0wSsBK4B1ASwBLAB1wSyBLIB2AS0BLoB2QS8BLwB4AS/BL8B4QTCBMYB4gTIBMgB5wTKBMsB6ATPBM8B6gTSBNIB6wTYBNgB7ATdBN0B7QToBOgB7gTqBOoB7wTxBPEB8AT1BPUB8QALADj/xADS/8QA1v/EATn/xAFF/8QDDv/EAxD/xAMS/8QDwf/EBHf/xAS//8QAGAA6ABQAOwAmAD0AFgEZABQCmQAWAyAAJgMiABYDJAAWA4sAFgOaABYDnQAWA9MAJgPVACYD1wAmA9kAFgPqABQD8gAWBHAAFgRyABYEdAAWBIYAFgTCABQExAAUBMYAJgABABP/CADnABD+7gAS/u4AJf9AAC7/MAA4ABQARf/eAEf/6wBI/+sASf/rAEv/6wBT/+sAVf/rAFb/5gBZ/+oAWv/oAF3/6ACU/+sAmf/rAJv/6gCy/0AAtP9AALv/6wC9/+gAyP/rAMn/6wDL/+oA0gAUANYAFAD3/+sBA//rAQ3/QAEY/+sBGv/oAR7/6wEi/+sBOQAUAUL/6wFFABQBYP/rAWH/6wFr/+sBhv7uAYr+7gGO/u4Bj/7uAev/wAHt/8ACM//AAn//QAKA/0ACgf9AAoL/QAKD/0AChP9AAoX/QAKa/94Cm//eApz/3gKd/94Cnv/eAp//3gKg/94Cof/rAqL/6wKj/+sCpP/rAqX/6wKr/+sCrP/rAq3/6wKu/+sCr//rArD/6gKx/+oCsv/qArP/6gK0/+gCtf/oArb/QAK3/94CuP9AArn/3gK6/0ACu//eAr3/6wK//+sCwf/rAsP/6wLF/+sCx//rAsn/6wLL/+sCzf/rAs//6wLR/+sC0//rAtX/6wLX/+sC5f8wAvn/6wL7/+sC/f/rAw4AFAMQABQDEgAUAxX/6gMX/+oDGf/qAxv/6gMd/+oDH//qAyP/6AMy/8ADM//AAzT/wAM1/8ADNv/AAzf/wAM4/8ADTf/AA07/wANP/8ADhv9AA47/QAOe/+sDov/qA6T/6wOm/+gDqf/qA6r/6wOr/+oDsv8wA7b/QAPBABQDw//eA8T/6wPG/+sDyP/rA8n/6APL/+sD0v/oA9r/6APi/0AD4//eA+b/6wPr/+gD7P/rA/H/6wPz/+gD+P9AA/n/3gP6/0AD+//eA///6wQB/+sEAv/rBAz/6wQO/+sEEP/rBBT/6AQW/+gEGP/oBB3/6wQe/0AEH//eBCD/QAQh/94EIv9ABCP/3gQk/0AEJf/eBCb/QAQn/94EKP9ABCn/3gQq/0AEK//eBCz/QAQt/94ELv9ABC//3gQw/0AEMf/eBDL/QAQz/94ENP9ABDX/3gQ3/+sEOf/rBDv/6wQ9/+sEP//rBEH/6wRD/+sERf/rBEv/6wRN/+sET//rBFH/6wRT/+sEVf/rBFf/6wRZ/+sEW//rBF3/6wRf/+sEYf/rBGP/6gRl/+oEZ//qBGn/6gRr/+oEbf/qBG//6gRx/+gEc//oBHX/6AR3ABQEmf9ABJr/3gSc/+sEoP/rBKT/6gSp/+sEq//rBL8AFATD/+gExf/oBMv/wATS/8AE6v/AADMAOP/fADr/5AA7/+wAPf/dANL/3wDW/98BGf/kATn/3wFF/98B6wAOAe0ADgIzAA4Cmf/dAw7/3wMQ/98DEv/fAyD/7AMi/90DJP/dAzIADgMzAA4DNAAOAzUADgM2AA4DNwAOAzgADgNNAA4DTgAOA08ADgOL/90Dmv/dA53/3QPB/98D0//sA9X/7APX/+wD2f/dA+r/5APy/90EcP/dBHL/3QR0/90Ed//fBIb/3QS//98Ewv/kBMT/5ATG/+wEywAOBNIADgTqAA4AHQA4/84AOv/tAD3/0ADS/84A1v/OARn/7QE5/84BRf/OApn/0AMO/84DEP/OAxL/zgMi/9ADJP/QA4v/0AOa/9ADnf/QA8H/zgPZ/9AD6v/tA/L/0ARw/9AEcv/QBHT/0AR3/84Ehv/QBL//zgTC/+0ExP/tABEALv/uADn/7gKV/+4Clv/uApf/7gKY/+4C5f/uAxT/7gMW/+4DGP/uAxr/7gMc/+4DHv/uA7L/7gRi/+4EZP/uBMH/7gBNAAYAEAALABAADQAUAEEAEgBH/+gASP/oAEn/6ABL/+gAVf/oAGEAEwCU/+gAmf/oALv/6ADI/+gAyf/oAPf/6AED/+gBHv/oASL/6AFC/+gBYP/oAWH/6AFr/+gBhAAQAYUAEAGHABABiAAQAYkAEAKh/+gCov/oAqP/6AKk/+gCpf/oAr3/6AK//+gCwf/oAsP/6ALF/+gCx//oAsn/6ALL/+gCzf/oAs//6ALR/+gC0//oAtX/6ALX/+gDnv/oA8T/6API/+gDy//oA9sAEAPcABAD3wAQA+b/6APs/+gD8f/oA///6AQB/+gEAv/oBA7/6AQd/+gEN//oBDn/6AQ7/+gEPf/oBD//6ARB/+gEQ//oBEX/6ARZ/+gEW//oBF3/6ARh/+gEnP/oBKn/6ASr/+gAAgD2/9YBhf+YAEAAR//sAEj/7ABJ/+wAS//sAFX/7ACU/+wAmf/sALv/7ADI/+wAyf/sAPf/7AED/+wBHv/sASL/7AFC/+wBYP/sAWH/7AFr/+wCof/sAqL/7AKj/+wCpP/sAqX/7AK9/+wCv//sAsH/7ALD/+wCxf/sAsf/7ALJ/+wCy//sAs3/7ALP/+wC0f/sAtP/7ALV/+wC1//sA57/7APE/+wDyP/sA8v/7APm/+wD7P/sA/H/7AP//+wEAf/sBAL/7AQO/+wEHf/sBDf/7AQ5/+wEO//sBD3/7AQ//+wEQf/sBEP/7ARF/+wEWf/sBFv/7ARd/+wEYf/sBJz/7ASp/+wEq//sABkAU//iARj/4gGFABgCq//iAqz/4gKt/+ICrv/iAq//4gL5/+IC+//iAv3/4gOk/+IDqv/iA8b/4gQM/+IEEP/iBEv/4gRN/+IET//iBFH/4gRT/+IEVf/iBFf/4gRf/+IEoP/iAAYAEP+EABL/hAGG/4QBiv+EAY7/hAGP/4QAEQAu/+wAOf/sApX/7AKW/+wCl//sApj/7ALl/+wDFP/sAxb/7AMY/+wDGv/sAxz/7AMe/+wDsv/sBGL/7ARk/+wEwf/sACAABv/yAAv/8gBa//MAXf/zAL3/8wD2//UBGv/zAYT/8gGF//IBh//yAYj/8gGJ//ICtP/zArX/8wMj//MDpv/zA8n/8wPS//MD2v/zA9v/8gPc//ID3//yA+v/8wPz//MEFP/zBBb/8wQY//MEcf/zBHP/8wR1//MEw//zBMX/8wA/ACf/8wAr//MAM//zADX/8wCD//MAk//zAJj/8wCz//MAxAANANP/8wEI//MBF//zARv/8wEd//MBH//zASH/8wFB//MBav/zAkX/8wJG//MCSP/zAkn/8wKG//MCkP/zApH/8wKS//MCk//zApT/8wK8//MCvv/zAsD/8wLC//MC0P/zAtL/8wLU//MC1v/zAvj/8wL6//MC/P/zAy3/8wOK//MDl//zA73/8wPA//MD7f/zA/D/8wQL//MEDf/zBA//8wRK//METP/zBE7/8wRQ//MEUv/zBFT/8wRW//MEWP/zBFr/8wRc//MEXv/zBGD/8wSf//MEuP/zAEAAJ//mACv/5gAz/+YANf/mAIP/5gCT/+YAmP/mALP/5gC4/8IAxAAQANP/5gEI/+YBF//mARv/5gEd/+YBH//mASH/5gFB/+YBav/mAkX/5gJG/+YCSP/mAkn/5gKG/+YCkP/mApH/5gKS/+YCk//mApT/5gK8/+YCvv/mAsD/5gLC/+YC0P/mAtL/5gLU/+YC1v/mAvj/5gL6/+YC/P/mAy3/5gOK/+YDl//mA73/5gPA/+YD7f/mA/D/5gQL/+YEDf/mBA//5gRK/+YETP/mBE7/5gRQ/+YEUv/mBFT/5gRW/+YEWP/mBFr/5gRc/+YEXv/mBGD/5gSf/+YEuP/mADgAJf/kADz/0gA9/9MAsv/kALT/5ADE/+IA2v/SAQ3/5AEz/9IBQ//SAV3/0gJ//+QCgP/kAoH/5AKC/+QCg//kAoT/5AKF/+QCmf/TArb/5AK4/+QCuv/kAyL/0wMk/9MDhv/kA4v/0wOO/+QDmv/TA5v/0gOd/9MDtv/kA8L/0gPZ/9MD4v/kA/L/0wP1/9ID+P/kA/r/5AQD/9IEHv/kBCD/5AQi/+QEJP/kBCb/5AQo/+QEKv/kBCz/5AQu/+QEMP/kBDL/5AQ0/+QEcP/TBHL/0wR0/9MEhv/TBJn/5AAoABD/RgAS/0YAJf/NALL/zQC0/80Ax//yAQ3/zQGG/0YBiv9GAY7/RgGP/0YCf//NAoD/zQKB/80Cgv/NAoP/zQKE/80Chf/NArb/zQK4/80Cuv/NA4b/zQOO/80Dtv/NA+L/zQP4/80D+v/NBB7/zQQg/80EIv/NBCT/zQQm/80EKP/NBCr/zQQs/80ELv/NBDD/zQQy/80ENP/NBJn/zQABAMQADgC5AEf/3ABI/9wASf/cAEv/3ABR/8EAUv/BAFP/1gBU/8EAVf/cAFn/3QBa/+EAXf/hAJT/3ACZ/9wAm//dALv/3AC9/+EAv//mAMH/wQDC/+sAw//pAMX/8ADG/+cAyP/cAMn/3ADK/+MAy//dAMz/zgDN/9QAzv/bAOz/wQDw/8EA8f/BAPP/wQD0/8EA9f/BAPf/3AD4/8EA+v/BAPv/wQD+/8EBAP/BAQP/3AEF/8EBGP/WARr/4QEe/9wBIv/cASv/wQE2/8EBPP/BAT7/wQFC/9wBU//BAVX/wQFX/8EBXP/BAWD/3AFh/9wBa//cAqH/3AKi/9wCo//cAqT/3AKl/9wCqv/BAqv/1gKs/9YCrf/WAq7/1gKv/9YCsP/dArH/3QKy/90Cs//dArT/4QK1/+ECvf/cAr//3ALB/9wCw//cAsX/3ALH/9wCyf/cAsv/3ALN/9wCz//cAtH/3ALT/9wC1f/cAtf/3ALy/8EC9P/BAvb/wQL3/8EC+f/WAvv/1gL9/9YDFf/dAxf/3QMZ/90DG//dAx3/3QMf/90DI//hA57/3AOg/8EDov/dA6T/1gOm/+EDqf/dA6r/1gOr/90DxP/cA8X/wQPG/9YDx//BA8j/3APJ/+EDy//cA8z/wQPR/8ED0v/hA9r/4QPh/8ED5v/cA+f/wQPr/+ED7P/cA/H/3APz/+ED///cBAH/3AQC/9wECP/BBAr/wQQM/9YEDv/cBBD/1gQU/+EEFv/hBBj/4QQc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/6sDm//wA53/qwOg/9IDtf/qA8H/nQPC//ADxf/SA8f/0gPM/9ID0f/SA9n/qwPb/8AD3P/AA9//wAPh/9ID5//SA+r/xwPy/6sD9f/wBAP/8AQI/9IECv/SBBP/6gQV/+oEF//qBBn/5QQc/9IEcP+rBHL/qwR0/6sEd/+dBHn/5QR8/9IEhv+rBJj/0gS1/9IEt//SBL//nQTC/8cExP/HAHUABv+xAAv/sQA4/54AOv/FADz/8gA9/6gAUf/PAFL/zwBU/88AXP/vAMH/zwDS/54A1v+eANr/8gDe/+wA4f/hAOb/wgDs/88A7v/vAPD/zwDx/88A8//PAPT/zwD1/88A9v/GAPj/zwD6/88A+//PAP7/zwEA/88BBf/PARn/xQEr/88BM//yATT/7wE2/88BOf+eATr/wAE8/88BPv/PAUP/8gFE/+8BRf+eAUf/4QFJ/+EBTP/fAVP/zwFV/88BV//PAVz/zwFd//IBXv/vAWL/zQFk/+gBbP+fAW3/xgGE/7EBhf+xAYf/sQGI/7EBif+xApn/qAKq/88C8v/PAvT/zwL2/88C9//PAw7/ngMQ/54DEv+eAyL/qAMk/6gDi/+oA5r/qAOb//IDnf+oA6D/zwO1/+wDwf+eA8L/8gPF/88Dx//PA8r/7wPM/88D0f/PA9n/qAPb/7ED3P+xA9//sQPh/88D5//PA+r/xQPy/6gD9f/yA/b/7wQD//IEBP/vBAj/zwQK/88EE//sBBX/7AQX/+wEGf/hBBz/zwRw/6gEcv+oBHT/qAR3/54Eef/hBHz/zwSG/6gEmP/PBLX/zwS3/88Ev/+eBML/xQTE/8UAUwA4/74AUf/hAFL/4QBU/+EAWv/vAF3/7wC9/+8Awf/hANL/vgDW/74A5v/JAOz/4QDw/+EA8f/hAPP/4QD0/+EA9f/hAPb/3wD4/+EA+v/hAPv/4QD+/+EBAP/hAQX/4QEJ/+0BGv/vASD/6wEr/+EBNv/hATn/vgE6/98BPP/hAT7/4QFF/74BTP/pAVP/4QFV/+EBV//hAVz/4QFj//UBbf/gAqr/4QK0/+8Ctf/vAvL/4QL0/+EC9v/hAvf/4QMO/74DEP++AxL/vgMj/+8DoP/hA6b/7wPB/74Dxf/hA8f/4QPJ/+8DzP/hA9H/4QPS/+8D2v/vA+H/4QPn/+ED6//vA/P/7wQI/+EECv/hBBT/7wQW/+8EGP/vBBz/4QRx/+8Ec//vBHX/7wR3/74EfP/hBJj/4QS1/+EEt//hBL//vgTD/+8Exf/vAGoAOP/mADr/5wA8//IAPf/nAFH/1gBS/9YAVP/WAFz/8QDB/9YA0v/mANb/5gDa//IA3v/uAOH/6ADm/+YA7P/WAO7/8QDw/9YA8f/WAPP/1gD0/9YA9f/WAPb/0AD4/9YA+v/WAPv/1gD+/9YBAP/WAQX/1gEZ/+cBK//WATP/8gE0//EBNv/WATn/5gE6/84BPP/WAT7/1gFD//IBRP/xAUX/5gFH/+gBSf/oAVP/1gFV/9YBV//WAVz/1gFd//IBXv/xAWL/5wFk/+0BbP/mAW3/0AKZ/+cCqv/WAvL/1gL0/9YC9v/WAvf/1gMO/+YDEP/mAxL/5gMi/+cDJP/nA4v/5wOa/+cDm//yA53/5wOg/9YDtf/uA8H/5gPC//IDxf/WA8f/1gPK//EDzP/WA9H/1gPZ/+cD4f/WA+f/1gPq/+cD8v/nA/X/8gP2//EEA//yBAT/8QQI/9YECv/WBBP/7gQV/+4EF//uBBn/6AQc/9YEcP/nBHL/5wR0/+cEd//mBHn/6AR8/9YEhv/nBJj/1gS1/9YEt//WBL//5gTC/+cExP/nAJgAJQAQACf/6AAr/+gAM//oADX/6AA4/+AAOv/gAD3/3wCD/+gAk//oAJj/6ACyABAAs//oALQAEADS/+AA0//oANQAEADW/+AA2QAUAN0AEADh/+EA5v/gAO0AEwDyABAA+f/gAQQAEAEI/+gBDQAQARf/6AEZ/+ABG//oAR3/6AEf/+gBIf/oATn/4AFB/+gBRf/gAUf/4QFI/+ABSf/hAUr/4AFN/+EBUAAQAVEAEAFY/+kBYv/fAWT/3gFmABABav/oAWz/3wFu//IBbwAQAXAAEAJF/+gCRv/oAkj/6AJJ/+gCfwAQAoAAEAKBABACggAQAoMAEAKEABAChQAQAob/6AKQ/+gCkf/oApL/6AKT/+gClP/oApn/3wK2ABACuAAQAroAEAK8/+gCvv/oAsD/6ALC/+gC0P/oAtL/6ALU/+gC1v/oAvj/6AL6/+gC/P/oAw7/4AMQ/+ADEv/gAyL/3wMk/98DLf/oA4YAEAOK/+gDi//fA44AEAOX/+gDmv/fA53/3wO2ABADvf/oA8D/6APB/+AD2f/fA+IAEAPq/+AD7f/oA/D/6APy/98D+AAQA/oAEAQL/+gEDf/oBA//6AQZ/+EEGv/gBB4AEAQgABAEIgAQBCQAEAQmABAEKAAQBCoAEAQsABAELgAQBDAAEAQyABAENAAQBEr/6ARM/+gETv/oBFD/6ARS/+gEVP/oBFb/6ARY/+gEWv/oBFz/6ARe/+gEYP/oBHD/3wRy/98EdP/fBHf/4AR5/+EEev/gBIb/3wSZABAEn//oBLj/6AS//+AEwv/gBMT/4AA1ABv/8gA4//EAOv/0ADz/9AA9//AA0v/xANT/9QDW//EA2v/0AN3/9QDe//MA5v/xARn/9AEz//QBOf/xAUP/9AFF//EBUP/1AV3/9AFi//IBZP/yAWb/9QFs//IBb//1Apn/8AMO//EDEP/xAxL/8QMi//ADJP/wA4v/8AOa//ADm//0A53/8AO1//MDwf/xA8L/9APZ//AD6v/0A/L/8AP1//QEA//0BBP/8wQV//MEF//zBHD/8ARy//AEdP/wBHf/8QSG//AEv//xBML/9ATE//QAawAlAA8AOP/mADr/5gA8AA4APf/mALIADwC0AA8A0v/mANQADgDW/+YA2QATANoADgDdAA4A3gALAOH/5QDm/+YA5//0AO0AEgDyAA8A9v/nAPn/6AD+/+cBBAAPAQ0ADwEZ/+YBMwAOATn/5gE6/+cBQwAOAUX/5gFH/+UBSP/oAUn/5QFK/+gBTP/kAVAADgFRAA8BXQAOAWL/5gFk/+YBZgAOAWz/5gFt/+cBbwAOAXAADwJ/AA8CgAAPAoEADwKCAA8CgwAPAoQADwKFAA8Cmf/mArYADwK4AA8CugAPAw7/5gMQ/+YDEv/mAyL/5gMk/+YDhgAPA4v/5gOOAA8Dmv/mA5sADgOd/+YDtQALA7YADwPB/+YDwgAOA9n/5gPiAA8D6v/mA/L/5gP1AA4D+AAPA/oADwQDAA4EEwALBBUACwQXAAsEGf/lBBr/6AQeAA8EIAAPBCIADwQkAA8EJgAPBCgADwQqAA8ELAAPBC4ADwQwAA8EMgAPBDQADwRw/+YEcv/mBHT/5gR3/+YEef/lBHr/6ASG/+YEmQAPBL//5gTC/+YExP/mADoABv+/AAv/vwA4/58AOv/JAD3/rQDS/58A1v+fAN7/7ADh/+YA5v/EAPb/zQD+/9UBGf/JATn/nwE6/8wBRf+fAUf/5gFJ/+YBTP/fAWL/0QFk/+wBbP+hAW3/zwGE/78Bhf+/AYf/vwGI/78Bif+/Apn/rQMO/58DEP+fAxL/nwMi/60DJP+tA4v/rQOa/60Dnf+tA7X/7APB/58D2f+tA9v/vwPc/78D3/+/A+r/yQPy/60EE//sBBX/7AQX/+wEGf/mBHD/rQRy/60EdP+tBHf/nwR5/+YEhv+tBL//nwTC/8kExP/JADEAOP/jADz/5QA9/+QA0v/jANT/5QDW/+MA2f/iANr/5QDd/+UA3v/pAPL/6gEE/+oBM//lATn/4wFD/+UBRf/jAVD/5QFR/+oBXf/lAWb/5QFs/+QBb//lAXD/6gKZ/+QDDv/jAxD/4wMS/+MDIv/kAyT/5AOL/+QDmv/kA5v/5QOd/+QDtf/pA8H/4wPC/+UD2f/kA/L/5AP1/+UEA//lBBP/6QQV/+kEF//pBHD/5ARy/+QEdP/kBHf/4wSG/+QEv//jACQAOP/iADz/5ADS/+IA1P/kANb/4gDZ/+EA2v/kAN3/5ADe/+kA7f/kAPL/6wEE/+sBM//kATn/4gFD/+QBRf/iAVD/5AFR/+sBXf/kAWb/5AFv/+QBcP/rAw7/4gMQ/+IDEv/iA5v/5AO1/+kDwf/iA8L/5AP1/+QEA//kBBP/6QQV/+kEF//pBHf/4gS//+IAGAA4/+sAPf/zANL/6wDW/+sBOf/rAUX/6wKZ//MDDv/rAxD/6wMS/+sDIv/zAyT/8wOL//MDmv/zA53/8wPB/+sD2f/zA/L/8wRw//MEcv/zBHT/8wR3/+sEhv/zBL//6wA5AFH/7wBS/+8AVP/vAFz/8ADB/+8A7P/vAO3/7gDu//AA8P/vAPH/7wDz/+8A9P/vAPX/7wD2/+4A+P/vAPr/7wD7/+8A/v/vAQD/7wEF/+8BCf/0ASD/8QEr/+8BNP/wATb/7wE6/+8BPP/vAT7/7wFE//ABU//vAVX/7wFX/+8BXP/vAV7/8AFt/+8Cqv/vAvL/7wL0/+8C9v/vAvf/7wOg/+8Dxf/vA8f/7wPK//ADzP/vA9H/7wPh/+8D5//vA/b/8AQE//AECP/vBAr/7wQc/+8EfP/vBJj/7wS1/+8Et//vACQABv/yAAv/8gBa//UAXf/1AL3/9QD2//QA/v/0AQn/9QEa//UBOv/1AW3/9QGE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/5gAyP+YAMn/mAD3/5gBA/+YARj/cAEe/5gBIv+YAUL/mAFg/5gBYf+YAWv/mAHB/xgCof+YAqL/mAKj/5gCpP+YAqX/mAKr/3ACrP9wAq3/cAKu/3ACr/9wAr3/mAK//5gCwf+YAsP/mALF/5gCx/+YAsn/mALL/5gCzf+YAs//mALR/5gC0/+YAtX/mALX/5gC+f9wAvv/cAL9/3ADBf8YAwf/GAMJ/xgDC/8YAw3/GAOe/5gDpP9wA6r/cAPE/5gDxv9wA8j/mAPL/5gDzf8YA+b/mAPs/5gD8f+YA///mAQB/5gEAv+YBAz/cAQO/5gEEP9wBB3/mAQ3/5gEOf+YBDv/mAQ9/5gEP/+YBEH/mARD/5gERf+YBEv/cARN/3AET/9wBFH/cART/3AEVf9wBFf/cARZ/5gEW/+YBF3/mARf/3AEYf+YBJz/mASg/3AEqf+YBKv/mAS+/xgAEwHT/+4B1f/1Adb/8QHY//IB9P/yAfj/8gIQ//ICEv/uAhT/8gNM/+4DeP/yA4D/9QOB/+4Dgv/uBND/7gTe/+4E4f/uBPX/8gT6/+4AEwHT/+UB1f/xAdb/6wHY/+kB9P/pAfj/6QIQ/+kCEv/lAhT/6QNM/+UDeP/pA4D/8QOB/+UDgv/lBND/5QTe/+UE4f/lBPX/6QT6/+UAAwHV//UB1v/uA4D/9QACAdb/twHb//AAAQBbAAsABAAN/+YAQf/0AGH/7wFN/+0AFgC4/9QAwv/tAMQAEQDK/+AAzP/nAM3/5QDO/+4A2QASAOr/6QD2/9cBOv/XAUr/0wFM/9YBTf/FAVj/5wFiAA0BZAAMAW3/1gFu//IB2//pAeX/5wIx/+kAAQEc//EAEgDZ/64A5gASAOv/4ADt/60A7//WAP3/3wEB/9IBB//gARz/zgEu/90BMP/iATj/4AFA/+ABSv/pAU3/2gFf/70Baf/fAWwAEQACAPb/9QGF/8AAAgDt/2gBHP/uAAoA5v/DAPb/zwD+/9QBOv/OAUn/5wFM/98BYv/RAWT/7AFs/6ABbf/RADAAVv9+AFv/nQBt/vEAfP70AIH+qwCG/14Aif9LALj/cgC//w8Aw/8KAMb/QQDH/wcAyv9oAMz/DwDN/w4Azv8MANn/YwDmAAUA6v+9AOv/SQDt/v4A7/8TAPb/aAD9/w4A/v9oAP//EwEB/wcBAgAw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AVAD6gPrAVED8AP7AVMD/gP/AV8EAQQEAWEECwQMAWUEEAQQAWcEEgQYAWgEHgRGAW8ESARIAZgESgRXAZkEXwRfAacEYgRiAagEZARkAakEcAR1AaoEdwR3AbAEewR8AbEEfwR/AbMEgQSCAbQEhASEAbYEhgSGAbcElwSbAbgEnQSdAb0EnwSgAb4EogSiAcAEpgSoAcEEqgSqAcQErASuAcUEsASwAcgEsgSyAckEtAS6AcoEvAS8AdEEvwS/AdIEwQTGAdMEyATLAdkEzwTPAd0E0gTSAd4E2ATYAd8E3QTdAeAE6AToAeEE6gTqAeIE8QTxAeME9QT1AeQAAgF0AAYABgAZAAsACwAZABAAEAAhABIAEgAhACUAJQACACYAJgAcACcAJwATACgAKAABACkAKQAFAC4ALgAKAC8ALwALADAAMAAYADMAMwABADQANAAWADgAOAAOADkAOQAKADoAOgAdADsAOwAbADwAPAASAD0APQAMAD4APgARAEUARQAGAEYARgAHAEcARwAXAEkASQAIAEwATAAEAFEAUgAEAFMAUwADAFQAVAAHAFYAVgAVAFoAWgAJAFwAXAAUAF0AXQAJAF4AXgAQAIoAigAHAJYAlgABALEAsQAiALIAsgACALMAswABALQAtAACAL0AvQAJAMEAwQAEAMcAxwAHANQA1QAgANoA2gASAN4A3gAlAOQA5AAgAOYA5gAgAOwA7AAaAO4A7gAUAPcA9wAHAPwA/AAfAP4A/gAfAP8A/wAHAQQBBQAfAQoBCgAfAQ0BDQACARgBGAADARkBGQAdARoBGgAJAS4BLgAHAS8BLwAiATABMAAaATMBMwASATQBNAAUATUBNQALATcBNwALATkBOQALAUMBQwASAUQBRAAUAVgBWAABAVwBXAAaAV0BXQASAV4BXgAUAYQBhQAZAYYBhgAhAYcBiQAZAYoBigAhAY4BjwAhAdgB2AAjAd0B3QANAeAB4AAkAeEB4QAeAesB6wAPAewB7AANAe0B7QAPAf8B/wAeAg4CEAAeAjACMAANAjMCMwAPAkUCRQATAkcCSAABAnoCewABAn0CfQAOAn8ChQACAoYChgATAocCigAFApAClAABApUCmAAKApkCmQAMApoCoAAGAqECoQAXAqICpQAIAqoCqgAEAqsCrwADArQCtQAJArYCtgAC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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAQAAAAAAAAACAAEAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgACAAYAAAAAAAAAAAAAAAAAAQAAAAkAAAAAAAAAAwAAAAAAAAAAAAAAAAABAAEAAAAFAAAAAAAAAAAAAAAAAAsAAgAZAAAACwAAAAAAAAARAAAAAAAZACIAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAFQAAAAMAAwAbAAMAAwADAAAAAQADACEAAwADAAAAAAADAAAAAwAAAAAAAQAbAAMAAAAAAAIAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAIABAAdAAkAAgAAAAIAAQACAAAAAgABAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAEQAVAAAAAwAAAAAACwAAAAAAAwAAAAMAAAAAAAIAAQARABUACwAAACAAIQAAAAAAAAAAAAAAAAAAABkAGwAAAAMAAAADAAAAAwAAAAAAAAAAAAMAEQAVAAAAAQABAAAAAAAAAAAAGQAAAAAAAAACAAEAAAAAAAAAGQAbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHwAfAAAAFAAUABoAFAAUABQAGgAAAAAAAAAaABoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXABwAJAAAABIAGAAeAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAANAAgADQAAAAAAAAAAAAAAAAAYAAgAAAAAABgAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAABgACAAXABwAGAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAIAAAACAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8AAAAAAAAAAAAAAAYABgAGAAYABgAGAAYAAgAAAAAAAAAAAAAAAAAAAAAAAAACAAIAAgACAAIACgAKAAoACgAMAAcABwAHAAcABwAHAAcAAQABAAEAAQABAAAAAAAAAAAAAwAEAAQABAAEAAQABQAFAAUABQAJAAkABgAHAAYABwAGAAcAAgABAAIAAQACAAEAAgABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAIAAQACAAEAAgABAAIAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAMAAAADAAMAAgAEAAIABAACAAQAAAAAAAAAAAAAAAAAEAAOABAADgAQAA4AEAAOABAADgALAAAACwAAAAsAAAAKAAUACgAFAAoABQAKAAUACgAFAAoABQAWAAAADAAJAAwAEwAPABMADwATAA8AAAAAAAIAAAAAAAAAAAANAA0ADQANAA0ADQANAAgAAAAAAAAAAAAAAAAAAAAAAAAACAAIAAgACAAIABIAEgASABIAFwANAA0ADQAIAAgACAAIAAAAAAAAAAAAAAAAAAgACAAIAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAIAAgAAAAAAAAAHgAeAB4AHgAAABgAAAASABIAEgASABIAEgAkABcAFwAAAAAAAAAGAAAAAAAAAAIADAAAAAAABgAAAAAAEwAAAAAAAAAAAAAAAgAAAAAADAARAAAADAABAAAAAwAAAAUAAAAEAAAACQAAAAAABQAEAAUAAAAAAAAAAAAAAAAAIwAAAAAAIgAGAAAAAAAAAAAAAAAAAAIAAAAAAAIACwARAAcAAQADAAQAAwABAAkAFQABAAMADgAAAAAAAAADAAkAFgAAABYAAAAWAAAADAAJABQAFAAAAAAAFAAAAAMABgAHAAAAAAABAAMAAAAAAB0ACQABAAIAAAAA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ACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQA+AGUAZwCBAIMAhACMAI8AkQCTALEAsgCzALQAtQC2ALcAuAC5ALoA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkBLwEzATUBNwE5ATsBQQFDAUUBSQFLAUwBWAFZAZcBnQGiAaUCegJ7An0CfwKAAoECggKDAoQChQKGAocCiAKJAooCiwKMAo0CjgKPApACkQKSApMClAKVApYClwKYApkCtgK4AroCvAK+AsACwgLEAsYCyALKAswCzgLQAtIC1ALWAtgC2gLcAt4C4ALiAuMC5QLnAukC6wLtAu8C8QLzAvUC+AL6AvwC/gMAAwIDBAMGAwgDCgMMAw4DEAMSAxQDFgMYAxoDHAMeAyADIgMkAyUDJwMpAysDLQOGA4cDiAOJA4oDiwOMA44DjwOQA5EDkgOTA5QDlQOWA5cDmAOZA5oDmwOcA50DrQOuA68DsAOxA7IDswO0A7UDtgO3A7gDuQO6A7sDvAO9A74DvwPAA8EDwgPTA9UD1wPZA+4D8APyBAcEDQQTBH0EggSGBQcFCQABAAAAAQAIAAIB3ADrAnECMwIyAjECMAIoAeYB5QHkAeMB4gHhAeAB3wHeAd0B3AHbAdoB2QHYAdcB1gHVAdQB0wHSAmQCcwMwAnUCdAMvAeMCcgJ3AlIE0gTTAeoB6wTUBNUE1gHsBNcB7QHuAe8E3AHwAfAE3QTeAfEB8gHzAfoE6wTsAfsB/AH9Af4B/wIABO8E8ATyBPUE/gICAgMCBAIFAgYCBwIIAgkCCgILAfQB9QH2AfcB+AH5AjsCDQIOAg8CEAT4AhECEwIUAhUCFwIZAnYDMQMyAzMDNAM1AzYDNwM4AzkDOgM7AzwDPQM+Az8DQANBA0IDQwNEA0UDRgNHA0gDSQNKA0sDTAOCA00DTgNPA1ADUQNSA1MDVANVA1YDVwNYA1kDWgNbA1wDXQNeA18DYANhA2IE/wNkA2UDZgNnA2gDaQNqA2sDbANtA24DbwNwA3EDcgNzA3QDdQUCA3YDdwN5A3gDegN7A3wDfQN+A38DgAOBA4MDhAOFBQAFAQTLBMwEzQTOBNgE2wTZBNoE3wTgBOEEzwTQBNEE6gTtBO4E8QTzBPQCAQT2BOIE4wTkBOUE5gTnBOgE6QUDBQQFBQUGBPcE+QT6AhgE/AIaBP0E+wIWAgwCEgULBQwAAQDrAAoARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAIUAhgCHAIkAigCLAI0AkACSAJQAuwC8AL0AvgC/AMAAwQDCAMMAxADFAMYAxwDIAMkAygDLAMwAzQDOAOoA6wDsAO0A7gDvAPAA8QDyAPMA9AD1APYA9wD4APkA+gD7APwA/QD+AP8BAAEBAQIBAwEEAQUBBgEHATABNAE2ATgBOgE8AUIBRAFGAUoBTQFaAnwCfgKaApsCnAKdAp4CnwKgAqECogKjAqQCpQKmAqcCqAKpAqoCqwKsAq0CrgKvArACsQKyArMCtAK1ArcCuQK7Ar0CvwLBAsMCxQLHAskCywLNAs8C0QLTAtUC1wLZAtsC3QLfAuEC5ALmAugC6gLsAu4C8ALyAvQC9gL5AvsC/QL/AwEDAwMFAwcDCQMLAw0DDwMRAxMDFQMXAxkDGwMdAx8DIQMjAyYDKAMqAywDLgOeA58DoAOhA6MDpAOlA6YDpwOoA6kDqgOrA6wDwwPEA8UDxgPHA8gDyQPKA8sDzAPNA84DzwPQA9ED0gPUA9YD2APaA+8D8QPzBAEECAQOBBQEfgR/BIMEhwUIBQoABgAAAAYAEgAqAEIAWgByAIoAAwAAAAEAEgABAJAAAQAAAAMAAQABAE0AAwAAAAEAEgABAHgAAQAAAAMAAQABAE4AAwAAAAEAEgABAGAAAQAAAAMAAQABAuEAAwAAAAEAEgABAEgAAQAAAAMAAQABA84AAwAAAAEAEgABADAAAQAAAAMAAQABA9AAAwAAAAEAEgABABgAAQAAAAMAAQABBEkAAgACAKgArAAAASQBJwAFAAEAAAABAAgAAgASAAYCYQJfAmICYwJgBQ0AAQAGAE0ATgLhA84D0ARJAAQAAAABAAgAAQYyADYAcgCkAK4AuADKAPwBDgEYAUoBZAF+AZABugH2AgACIgI8Ak4CigKcArYC4ALyAyQDLgM4A0oDfAOGA5ADmgO0A84D4AQKBDwERgRoBIIElATGBNgE8gUcBS4FOAVCBUwFVgWABaoF1AX+BigABgAOABQAGgAgACYALAKAAAIAqQQeAAIArQJ/AAIAqAQgAAIAqwKCAAIAqgSZAAIArAABAAQEpgACAK0AAQAEArwAAgCpAAIABgAMBKoAAgG6BKgAAgCtAAYADgAUABoAIAAmACwCiAACAKkENgACAK0ChwACAKgEOAACAKsEOgACAKoEmwACAKwAAgAGAAwElQACAKkC1gACAboAAQAEBKwAAgCtAAYADgAUABoAIAAmACwCjAACAKkESAACAK0CiwACAKgERgACAKsC2gACAKoEnQACAKwAAwAIAA4AFASuAAIAqQLnAAIBugSwAAIArQADAAgADgAUAukAAgCpAusAAgG6BLIAAgCtAAIABgAMA+AAAgCpBLQAAgCtAAUADAASABgAHgAkAvEAAgCpAvMAAgG6BLYAAgCtBJcAAgCoAo8AAgCqAAcAEAAYAB4AJAAqADAANgS4AAMAqgCpApEAAgCpBEoAAgCtApAAAgCoBEwAAgCrApMAAgCqBJ8AAgCsAAEABAS5AAIAqQAEAAoAEAAWABwC/gACAKkDAAACAboEuwACAK0EoQACAKwAAwAIAA4AFAMEAAIAqQMKAAIBugS9AAIArQACAAYADAMOAAIBugS/AAIArQAHABAAGAAeACQAKgAwADYEwQADAKoAqQKWAAIAqQRiAAIArQKVAAIAqARkAAIAqwMUAAIAqgSjAAIArAACAAYADATEAAIArQTCAAIAqgADAAgADgAUA9UAAgCpBMYAAgCtA9MAAgCoAAUADAASABgAHgAkApkAAgCpBHAAAgCtA9kAAgCoBHIAAgCrBHQAAgCqAAIABgAMAyUAAgCpBMgAAgCtAAYADgAUABoAIAAmACwCmwACAKkEHwACAK0CmgACAKgEIQACAKsCnQACAKoEmgACAKwAAQAEBKcAAgCtAAEABAK9AAIAqQACAAYADASrAAIBugSpAAIArQAGAA4AFAAaACAAJgAsAqMAAgCpBDcAAgCtAqIAAgCoBDkAAgCrBDsAAgCqBJwAAgCsAAEABASWAAIAqQABAAQErQACAK0AAQAEBEkAAgCtAAMACAAOABQErwACAKkC6AACAboEsQACAK0AAwAIAA4AFALqAAIAqQLsAAIBugSzAAIArQACAAYADAPhAAIAqQS1AAIArQAFAAwAEgAYAB4AJALyAAIAqQL0AAIBugS3AAIArQSYAAIAqAKqAAIAqgAGAA4AFAAaACAAJgAsAqwAAgCpBEsAAgCtAqsAAgCoBE0AAgCrAq4AAgCqBKAAAgCsAAEABAS6AAIAqQAEAAoAEAAWABwC/wACAKkDAQACAboEvAACAK0EogACAKwAAwAIAA4AFAMFAAIAqQMLAAIBugS+AAIArQACAAYADAMPAAIBugTAAAIArQAGAA4AFAAaACAAJgAsArEAAgCpBGMAAgCtArAAAgCoBGUAAgCrAxUAAgCqBKQAAgCsAAIABgAMBMUAAgCtBMMAAgCqAAMACAAOABQD1gACAKkExwACAK0D1AACAKgABQAMABIAGAAeACQCtAACAKkEcQACAK0D2gACAKgEcwACAKsEdQACAKoAAgAGAAwDJgACAKkEyQACAK0AAQAEAysAAgCpAAEABAMtAAIAqQABAAQDLAACAKkAAQAEAy4AAgCpAAUADAASABgAHgAkAqcAAgCpAqYAAgCoBEcAAgCrAtsAAgCqBJ4AAgCsAAUADAASABgAHgAkBFgAAgCpBGAAAgCtBFoAAgCoBFwAAgCrBF4AAgCqAAUADAASABgAHgAkBFkAAgCpBGEAAgCtBFsAAgCoBF0AAgCrBF8AAgCqAAUADAASABgAHgAkBGYAAgCpBG4AAgCtBGgAAgCoBGoAAgCrBGwAAgCqAAUADAASABgAHgAkBGcAAgCpBG8AAgCtBGkAAgCoBGsAAgCrBG0AAgCqAAEABASlAAIAqQACABEAJQApAAAAKwAtAAUALwA0AAgANgA7AA4APQA+ABQARQBJABYASwBNABsATwBUAB4AVgBbACQAXQBeACoAgQCBACwAgwCDAC0AhgCGAC4AiQCJAC8AjQCNADAAmACbADEA0ADQADUAAQAAAAEACAABAAYAAgABAAIDCAMJAAEAAAABAAgAAgASAAYFBwUIBQkFCgULBQwAAQAGAroCuwLMAs0DTwNYAAEAAAABAAgAAQAGAAEAAQABAXsABAAAAAEACAABAEAAAQAIAAIABgAOAb4AAwBKAE0BvAACAE0ABAAAAAEACAABABwAAQAIAAIABgAOAb8AAwBKAFABvQACAFAAAQABAEoABAAAAAEACAABACoAAwAMABYAIAABAAQBuwACAEoAAQAEAcEAAgBYAAEABAHAAAIAWAABAAMASgBXAJUAAQAAAAEACAABAAYB3gABAAEASwABAAAAAQAIAAEABgFvAAEAAQC7AAEAAAABAAgAAQAGAfUAAQABADYAAQAAAAEACAACABwAAgIsAi0AAQAAAAEACAACAAoAAgIuAi8AAQACAC8ATwABAAAAAQAIAAIAHgAMAkUCRwJGAkgCSQJnAmgCaQJqAmsCbAJtAAEADAAnACgAKwAzADUARgBHAEgASwBTAFQAVQABAAAAAQAIAAIADAADAm4CbwJvAAEAAwBJAEsCagABAAAAAQAIAAIALgAUAloCXgJYAlUCVwJWAlsCWQJdAlwCTwJKAksCTAJNAk4AGgAcAlMCZQACAAQAFAAdAAACZgJmAAoCcAJwAAsEjQSUAAwAAQAAAAEACAACAC4AFASUAnAEjQSOBI8EkASRAmYEkgSTAkwCTgJNAksCTwJlABoCUwAcAkoAAgACABQAHQAAAlUCXgAKAAEAAAABAAgAAgAuABQCWwJdAl4CWAJVAlcCVgJZAlwCWgAbABUAFgAXABgAGQAaABwAHQAUAAEAFAAaABwCSgJLAkwCTQJOAk8CUwJlAmYCcASNBI4EjwSQBJEEkgSTBJQAAQAAAAEACAACAC4AFASRBJICcASNBI4EjwSQAmYEkwAXABkAGAAWABsAFAAaAB0AHAAVBJQAAgAGABoAGgAAABwAHAABAkoCTwACAlMCUwAIAlUCXgAJAmUCZQATAAEAAAABAAgAAQAGAYEAAQABABMABgAAAAEACAADAAEAEgABAGwAAAABAAAAGAACAAMBlAGUAAABxQHHAAECHwIlAAQAAQAAAAEACAACADwACgHHAcYBxQIfAiACIQIiAiMCJAIlAAEAAAABAAgAAgAaAAoCPgB6AHMAdAI/AkACQQJCAkMCRAACAAEAFAAdAAA=) -} - -@font-face { - font-family: Roboto; - font-weight: 400; - font-style: italic; - src: url(data:font/ttf;base64,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BcgCJgCdAAABBwBqAI8AAQAMALAAL7A43LAj0DAx////rAAAB3UHCQImANoAAAEHAGoCMQFCAAwAsAkvsCvcsBbQMDH///+lAAAGDgWzAiYA7gAAAQcAagFh/+wADACwCS+wK9ywFtAwMf//ACX/6gSYBx4CJgDbAAABBwBqAPgBVwAMALANL7BA3LAr0DAx//8AIf/qA7gFxwImAO8AAAEGAGpnAAAMALANL7A93LAo0DAx//8AQwAABW4G7wImANwAAAEHAHABQQFKAAkAsAAvsArcMDEA//8ALwAABDcFmQImAPAAAAEGAHB79AAJALAAL7AK3DAxAP//AEMAAAVuBwkCJgDcAAABBwBqAXABQgAMALAAL7Af3LAK0DAx//8ALwAABDcFswImAPAAAAEHAGoAqv/sAAwAsAAvsB/csArQMDH//wB3/+cFDQb/AiYAMwAAAQcAagFUATgADACwCi+wONywI9AwMf//AEX/6AQfBccCJgBTAAABBwBqAJMAAAAMALAAL7A43LAj0DAx//8Aaf/pBPwFyAIGARcAAP//AEL/5wQgBFMCBgEYAAD//wBp/+kE/AcEAiYBFwAAAQcAagFgAT0ADACwCS+wOtywJdAwMf//AEL/5wQgBckCJgEYAAABBwBqAJAAAgAMALAEL7A13LAg0DAx//8AdP/pBPwHHwImAOcAAAEHAGoBTAFYAAwAsBUvsDjcsCPQMDH//wA0/+cD1QXHAiYA/wAAAQcAagCEAAAADACwCC+wN9ywItAwMf//AJP/5gVABu8CJgDeAAABBwBwAOwBSgAJALABL7AR3DAxAP///6X+RQPsBa0CJgBdAAABBgBwLwgACQCwAS+wENwwMQD//wCT/+YFQAcJAiYA3gAAAQcAagEbAUIADACwAS+wJtywEdAwMf///6X+RQPsBccCJgBdAAABBgBqXgAADACwAS+wJdywENAwMf//AJP/5gVAB0ECJgDeAAABBwCmAV0BQgAWALAARViwAS8bsQEdPlmwE9ywF9AwMf///6X+RQReBf8CJgBdAAABBwCmAKAAAAAWALAARViwAS8bsQEZPlmwEtywFtAwMf//AM4AAAVEBwkCJgDhAAABBwBqAUQBQgAWALAARViwEi8bsRIdPlmwKNywHNAwMf//AHsAAAQABbMCJgD5AAABBgBqaewADACwCC+wKNywE9AwMf//AEUAAAaWBwkAJgDmDwAAJwAtBJUAAAEHAGoCCAFCABYAsABFWLAKLxuxCh0+WbAh3LAt0DAx//8AMAAABakFswAmAP4AAAAnAI0ECgAAAQcAagFq/+wAFgCwAEVYsAovG7EKGT5ZsCHcsC3QMDH//wBL/+gEdQYAAgYASAAA////r/6fBIsFsAImACUAAAAHAK0E3AAA//8AM/6fA88EUQImAEUAAAAHAK0EKQAA////rwAABIsHuQImACUAAAEHAKsFAQFGAAkAsAQvsBjcMDEA//8AM//oA88GgwImAEUAAAEHAKsEcwAQAAkAsBgvsDncMDEA////rwAABe0HwwImACUAAAEHAjcA8gEuABYAsABFWLAFLxuxBR0+WbAO3LAU0DAx//8AM//oBV8GjgImAEUAAAEGAjdk+QAWALAARViwGC8bsRgZPlmwL9ywNdAwMf///68AAASLB78CJgAlAAABBwI4APgBPQAWALAARViwBS8bsQUdPlmwDNywE9AwMf//ADP/6AP9BokCJgBFAAABBgI4agcAFgCwAEVYsBgvG7EYGT5ZsC/csDTQMDH///+vAAAFbAfqAiYAJQAAAQcCOQDzARsAFgCwAEVYsAUvG7EFHT5ZsAzcsCDQMDH//wAz/+gE3ga1AiYARQAAAQYCOWXmABYAsABFWLAYLxuxGBk+WbAv3LAz0DAx////rwAABIsH2QImACUAAAEHAjoA7wEGABYAsABFWLAELxuxBB0+WbAO3LAV0DAx//8AM//oA/cGpAImAEUAAAEGAjph0QAWALAARViwGC8bsRgZPlmwLdywNtAwMf///6/+nwSLBzYCJgAlAAAAJwCeAPkBNgEHAK0E3AAAABMAsABFWLAELxuxBB0+WbAQ3DAxAP//ADP+nwPPBgACJgBFAAAAJgCeawABBwCtBCkAAAATALAARViwGC8bsRgZPlmwMdwwMQD///+vAAAEiwe3AiYAJQAAAQcCPAEXAS0ADACwBC+wDtywGtAwMf//ADP/6APlBoICJgBFAAABBwI8AIn/+AAMALAYL7Av3LA70DAx////rwAABIsHtwImACUAAAEHAjUBFwEtAAwAsAQvsA7csBrQMDH//wAz/+gD5QaCAiYARQAAAQcCNQCJ//gADACwGC+wL9ywO9AwMf///68AAASL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AAAAAAOWAGQAAAAAAAAAAAH2AAAB9gAAAgkAQwKFAMgE0QBSBGYASgW5ALsE3QA6AWQAqgKxAG0Cvf+PA2IAawRwAEwBkP+PAi4AGQIVADUDPf+PBGYAaARmAPkEZgAXBGYANARmAAUEZgByBGYAcARmAJ0EZgBBBGYAlAHrACsBrv+bA/wAQQRMAHAEGAA6A7QApQcCAEQFGv+vBN8AOwUXAHQFIQA7BHMAOwRUADsFUwB5BZIAOwImAEkEUgAKBOcAOwQ3ADsG0AA7BZIAOwVgAHcE7wA7BWAAbwTRADoEpQAnBKsAqAUSAGcE+gCkBuwAwwTn/9QEswCoBK//6wIZ//8DOQC/Ahn/egNIAE8Div+BAnAA0ARDADMEZQAfBBoARgRqAEsEJgBFArwAdARlAAQEUAAfAewALwHk/xQD+QAgAewALwbXAB4EUgAfBHcARQRl/9cEcwBJAqoAHwQKAC4CkwBDBFEAWwPMAG4F3wCAA+P/xAO2/6UD4//tAqoAOAHuACECqv+MBVEAaQHu//EESABSBIz/8wWSABIEHQBDAeb/9wTM/90DSADaBiMAYgOCAMMDrgBZBFYAgQYkAGEDmAD3AvAA6AQvACUC4gBcAuIAbgJ5ANUEb//lA9UAewIQAKUB9v/IAuIA3gORAMADrQAPBbkAuQYPALQGEwCeA7b/0wdL/4QELQAoBWAAIASgADgEpwAeBpcAEwSWAFwEeABEBG8AOQSD/+AErABLBXkANQH1AC4EWwAtBDgAIgIiACMFagA1BG8AJAdwAFQHFgBHAfcAMwVnAFECrv9JBV4AZwR5AEIFbwBnBNcAWgH+/wkEIQA+A7EBFwN8AScDmQD3A1oBBwHsAQ4CogEBAiP/rwOzAN0C7wDCAlL/6QAA/WoAAP3rAAD9CwAA/fUAAPzbAAD8uwIHASED9gDzAhEApQRbAEMFg/+xBVEAaQUg/8QEeAAMBZMARAR4/9oFmQBVBWgAhgUzAAoEbABIBKP/8APtAIQEbwBDBDkAKQQPAIIEbwAkBHUAcwKNAIUEVv+3A9gAPwSpAGAEb//cBDYATgRvAEoEFgCHBEUAZwWCAEEFeQBPBm4AZgSHAFEEKwBnBiIAZgXbAKEFRQB4CFn/zAhsAEMGWgC0BZIAQgTuADQF4P+LBxX/rASlACUFkgBDBYj/ygTqAJMGBwBbBbYAQQVaAM4HVwBCB44AQgXtAIkGwABFBOgANgVFAHQG+gBJBPv/6ARUAEYEeQAwA0sALQS5/40F+/+lA/sAIQSFAC8EOwAvBIb/yAXLADAEhAAvBIUALwPEAGAFqgBMBKMALwRCAHsGUAAvBnUAJATbAFYGEAAwBEEAMAQ2ADQGXwAwBEz/vwRQAB8ENgBOBp//wwa5AC8EcAAfBIUALwbcAG8GBgBPBD8ALgb+AEkF1AAsBLf/ugQv/6IG3wBaBecATganACYFvgApCMkASAefAC4EDf/OA8f/ygVRAGkEcgBCBO0ArQPuAIQFUQBqBG8ARAbVAHQF/wBSBtwAbwYGAE8FFABmBDAATQThAEAAAPzoAAD9CwAA/hcAAP47AAD6OAAA+k8F5QBDBNEALwQ/AC4E/gA6BHD/1wRLADUDfwAkBMAAQwPwACQHcf+sBjr/pQV5AEQEngAvBOwANgRmAC0GZAC7BWMAdAXbADsEvgAvB50AOgWSACQH/ABCBskAJAXKAHEEuABfBPv/1AQU/8QG/wCsBT0AVwWaAM4EfQB7BU8AxARSAJgFTwAcBgoAigSjAAcE7AA1BEMALQXa/8oE0//IBZAAQwRvACQF7QA7BNAALwchADsGGAAwBWcAUQSOADwEjv/8BJ3/+AOZ/+kFEP/UBCn/xATaADEGawAyBrkATAYvAK0FDQBoBDIArwPyAKAHj//fBk3/2gfIADsGeAAjBNoAagQHAEwFiwCaBQMAfQVFAGoF3v/KBNb/yAMSAPID/wAAB/QAAAP/AAAH9AAAAq4AAAIEAAABXAAABGYAAAIpAAABnwAAAQIAAADVAAAAAAAAAi0AGQItABkFIgCnBhkAmQOT/14BlwCuAZcAiQGV/5gBlwDUAsgAtgLPAJUCtv+UBFEAdwR2//YCpwCgA7EAOQU7ADkBfQBSB3kAlwJeAF8CXgACA5H/7wLiAGMDUAB+BIz/8wYuAAoGaAA5CD8AOgXIAAkGBgAfBGYAUQW3AEMEDABJBFwACgUp//IFMP/lBcQAzAO7AEsIBQA1BOUA6gT6AIIGAQC1BqwAkgalAI8GQwC+BHYATQVtACQElf+sBHkAqwSqAEEIBQBNAgb/GgRpADEETABwA/z/1AQZABkD8wBBAkQAeAKFAHAB/v/jBNcAdARWAFgEcgB0BqoAdAaqAHQE0gB0BnIAKQAAAAAH/v+rCDUAXALi/+kC4gBrAuIAHQP6AGsD+gAoA/oAcAP5AEsD+gBKA/r/9wP6ABYD+v/9A/oAvAP6AEoEDf/cBBUAdAQ9/7YF8ACVBE8AegRkAEUEEABtBAoAEQQzAB0EoQBFBEUAHQShAEoExwAdBd4AHQOiAB0EPQAdA7z/9gHjACoExwAdBJIATAO4AB0ECgASBB0ABgOPABkDnQAdBE//sAShAEoET/+wA3j/0wSzAB0D2//VBUgAUQT6AH4E1gAMBVIAbARkAEcHE//EByEAHQVUAG0EsgAdBEIAHwUH/4kF5/+vBCgAEQTQAB8ENwAeBKb/xAQJAFgFCgAdBFIAWgYqAB0GgwAdBQAAUAXNAB8ENwAfBGMAIAZOAB0Ebv/fA/z/+gYh/68EYQAeBOwAHgUZAGkFoABQBEcAdASO/7YGOgBsBFIAWgRSAB0FoQAvBK8AQQQoABEEoQBKBB3//wPPAB4H7gAdBJH/3QLi//sC4v/wAuIAFgLiAB4C4gAvAuIACwLiADYDhACTAqoBCwPSAB0EJP+aBKgASwUtAEMFBwBEA/4AJQUfAEQD+gAlBGcAHQRkAEcEOQAdBGz/pQH4APwDkgERAAD9KgPbANID3wAiA/kAzgPgAM0DnQAdA40BEQOMARIC4gCQAuIAYwLiAIkC4gCRAuIAogLiAH4C4gCpBWEAgQWMAIQFcgBEBb0AhQXAAIUDwgC7BGkAOQRB/4EEtP/TBFP/1QQYACsDkgETAY//vQZ7AEkEnwA/Aff/DwRm/6wEZv/jBGb/uQRmAC0EZgBWBGYAJQRmAGoEZgAdBGYAQQRmAQwCAP8JAf//CQH2AC4B9v96AfYALgQ5AB0E5ABkBAoAYgRlAB8EHABDBHoARwRzACQEhQBBBHT/1wSDAEYEJgBFBGUANQNoAKkEuwArA6L/6AYT/5oD5AAdBKH/9ATHAB0ExwAdAfYAAAIuABkFPwARBT8AEQRuAD0EqwCoApP/9AUa/68FGv+vBRr/rwUa/68FGv+vBRr/rwUa/68FFwB0BHMAOwRzADsEcwA7BHMAOwImAEkCJgBJAiYASQImAEkFkgA7BWAAdwVgAHcFYAB3BWAAdwVgAHcFEgBnBRIAZwUSAGcFEgBnBLMAqARDADMEQwAzBEMAMwRDADMEQwAzBEMAMwRDADMEGgBGBCYARQQmAEUEJgBFBCYARQH1AC4B9QAuAfUALgH1AC4EUgAfBHcARQR3AEUEdwBFBHcARQR3AEUEUQBbBFEAWwRRAFsEUQBbA7b/pQO2/6UFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMFFwB0BBoARgUXAHQEGgBGBRcAdAQaAEYFFwB0BBoARgUhADsFAABLBHMAOwQmAEUEcwA7BCYARQRzADsEJgBFBHMAOwQmAEUEcwA7BCYARQVTAHkEZQAEBVMAeQRlAAQFUwB5BGUABAVTAHkEZQAEBZIAOwRQAB8CJgBJAfUAEQImAEkB9QAuAiYASQH1AC4CJv+OAez/cAImAEkGeABJA9AALwRSAAoB/v8JBOcAOwP5ACAENwA7AewALwQ3ADsB7P+jBDcAOwKCAC8ENwA7AsgALwWSADsEUgAfBZIAOwRSAB8FkgA7BFIAHwRSAB8FYAB3BHcARQVgAHcEdwBFBWAAdwR3AEUE0QA6AqoAHwTRADoCqv+fBNEAOgKqAB8EpQAnBAoALgSlACcECgAuBKUAJwQKAC4EpQAnBAoALgSlACcECgAuBKsAqAKTAEMEqwCoApMAQwSrAKgCuwBDBRIAZwRRAFsFEgBnBFEAWwUSAGcEUQBbBRIAZwRRAFsFEgBnBFEAWwUSAGcEUQBbBuwAwwXfAIAEswCoA7b/pQSzAKgEr//rA+P/7QSv/+sD4//tBK//6wPj/+0HS/+EBpcAEwVgACAEbwA5BGf/sARn/7AEEABtBGz/pQRs/6UEbP+lBGz/pQRs/6UEbP+lBGz/pQRkAEcD0gAdA9IAHQPSAB0D0gAdAeMAKgHjACoB4wAqAeMAKgTHAB0EoQBKBKEASgShAEoEoQBKBKEASgRkAEUEZABFBGQARQRkAEUEFQB0BGz/pQRs/6UEbP+lBGQARwRkAEcEZABHBGQARwRnAB0D0gAdA9IAHQPSAB0D0gAdA9IAHQSSAEwEkgBMBJIATASSAEwExwAdAeMADwHjACoB4wAqAeP/egHjACoDvP/2BD0AHQOiAB0DogAdA6IAHQOiAB0ExwAdBMcAHQTHAB0EoQBKBKEASgShAEoEMwAdBDMAHQQzAB0ECgARBAoAEQQKABEECgARBBAAbQQQAG0EEABtBGQARQRkAEUEZABFBGQARQRkAEUEZABFBfAAlQQVAHQEFQB0BA3/3AQN/9wEDf/cBRr/rwRz/58Fkv+tAib/swV0AFYFF/+KBUcAHgKNACAFGv+vBN8AOwRzADsEr//rBZIAOwImAEkE5wA7BtAAOwWSADsFYAB3BO8AOwSrAKgEswCoBOf/1AImAEkEswCoBGwASAQ5ACkEbwAkAo0AhQRFAGcEWwAtBHcARQRv/+UDzABuA+P/xAKNAGYERQBnBHcARQRFAGcGbgBmBHMAOwRbAEMEpQAnAiYASQImAEkEUgAKBQcARATnADsE6gCTBRr/rwTfADsEWwBDBHMAOwWSAEMG0AA7BZIAOwVgAHcFkwBEBO8AOwUXAHQEqwCoBOf/1ARDADMEJgBFBIUALwR3AEUEZf/XBBoARgO2/6UD4//EBCYARQNLAC0ECgAuAewALwH1AC4B5P8UBDsALwO2/6UG7ADDBd8AgAbsAMMF3wCABuwAwwXfAIAEswCoA7b/pQFkAKoChQDIBBIAQwH+/wkBlwCJBtAAOwbXAB4FGv+vBEMAMwRzADsFkgBDBCYARQSFAC8FaACGBXkATwTtAK0D7gCECC0ARQkWAHcEpQAlA/sAIQUXAHQEGgBGBLMAqAPtAIQCJgBJBxX/rAX7/6UCJgBJBRr/rwRDADMFGv+vBEMAMwdL/4QGlwATBHMAOwQmAEUFZwBRBCEAPgQhAD4HFf+sBfv/pQSlACUD+wAhBZIAQwSFAC8FkgBDBIUALwVgAHcEdwBFBVEAaQRyAEIFUQBpBHIAQgVFAHQENgA0BOoAkwO2/6UE6gCTA7b/pQTqAJMDtv+lBVoAzgRCAHsGwABFBhAAMARqAEsFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMEcwA7BCYARQRzADsEJgBFBHMAOwQmAEUEcwA7BCYARQRzADsEJgBFBHMAOwQmAEUEcwA7BCYARQRzADsEJgBFAiYASQH1AC4CJgAOAez/8QVgAHcEdwBFBWAAdwR3AEUFYAB3BHcARQVgAHcEdwBFBWAAdwR3AEUFYAB3BHcARQVgAHcEdwBFBV4AZwR5AEIFXgBnBHkAQgVeAGcEeQBCBV4AZwR5AEIFXgBnBHkAQgUSAGcEUQBbBRIAZwRRAFsFbwBnBNcAWgVvAGcE1wBaBW8AZwTXAFoFbwBnBNcAWgVvAGcE1wBaBLMAqAO2/6UEswCoA7b/pQSzAKgDtv+lBIgAAASrAKgDxABgBVoAzgRCAHsEWwBDA0sALQYKAIoEowAHBFAAHwToACsE6AArBFsAEANL/+YFGwBJBBIAKwSzAKgD7QBdBOf/1APj/8QEOQApBFT/1wYZAJkEZgAXBGYANARmAAUEZgByBHoAhASOAFUEegCUBI4AfAVTAHkEZQAEBZIAOwRSAB8FGv+vBEMAMwRzADsEJgBFAib/3wH1/40FYAB3BHcARQTRADoCqgAfBRIAZwRRAFsEj/9OBN8AOwRlAB8FIQA7BGoASwUhADsEagBLBZIAOwRQAB8E5wA7A/kAIATnADsD+QAgBDcAOwHs//IG0AA7BtcAHgWSADsEUgAfBWAAdwTvADsEZf/XBNEAOgKq/+4EpQAnBAoALgSrAKgCkwBDBRIAZwT6AKQDzABuBPoApAPMAG4G7ADDBd8AgASv/+sD4//tBab+xgRs/6UEDv+lBQP/wQIf/8UEqwATBFH/XwTgABYEbP+lBDkAHQPSAB0EDf/cBMcAHQHjACoEPQAdBd4AHQTHAB0EoQBKBEUAHQQQAG0EFQB0BD3/tgHjACoEFQB0A9IAHQOdAB0ECgARAeMAKgHjACoDvP/2BD0AHQQJAFgEbP+lBDkAHQOdAB0D0gAdBNAAHwXeAB0ExwAdBKEASgSzAB0ERQAdBGQARwQQAG0EPf+2BCgAEQTHAB0EZABIBBUAdAWhAC8E0AAfBAkAWAVIAFEFnwAqBhP/mgSh//QECgARBfAAlQXwAJUF8ACVBBUAdAUa/68EQwAzBHMAOwQmAEUEbP+lA9IAHQH1//EAAQAAB2z+DAAACRb6OP5sCUwIAAGzAAAAAAAAAAAAAAAABQ4AAwRvAZAABQAABZoFMwAAAR8FmgUzAAAD0QBmAgAAAAIAAAAAAAAAAADgAAL/UAAgWwAAACAAAAAAR09PRwABAAD//QYA/gAAZgeaAgAgAAGfAAAAAAQ6BbAAIAAgAAMAAAABAAAFEAkKBAAAAgICAwUFBgUCAwMEBQICAgQFBQUFBQUFBQUFAgIEBQUECAYFBgYFBQYGAgUGBQgGBgYGBQUFBgYIBgUFAgQCBAQDBQUFBQUDBQUCAgQCCAUFBQUDBQMFBAcEBAQDAgMGAgUFBgUCBQQHBAQFBwQDBQMDAwUEAgIDBAQGBwcECAUGBQUHBQUFBQUGAgUFAgYFCAgCBgMGBQYFAgUEBAQEAgMCBAMDAAAAAAAAAgQCBQYGBgUGBQYGBgUFBAUFBQUFAwUEBQUFBQUFBgYHBQUHBwYJCQcGBgcIBQYGBgcGBggJBwgGBggGBQUEBQcEBQUFBwUFBAYFBQcHBQcFBQcFBQUHCAUFCAcFCAcFBQgHBwYKCQUEBgUGBAYFCAcIBwYFBQAAAAAAAAcFBQYFBQQFBAgHBgUGBQcGBwUJBgkIBwUGBQgGBgUGBQYHBQYFBwUGBQcFCAcGBQUFBAYFBQcIBwYFBAkHCQcFBQYGBgcFAwUJBQkDAgIFAgIBAQACAgYHBAICAgIDAwMFBQMEBgIIAwMEAwQFBwcJBwcFBgUFBgYGBAkGBgcIBwcFBgUFBQkCBQUEBQQDAwIFBQUICAUHAAkJAwMDBAQEBAQEBAQEBAUFBQcFBQUFBQUFBQUHBAUEAgUFBAUFBAQFBQUEBQQGBgUGBQgIBgUFBgcFBQUFBQYFBwcGBwUFBwUEBwUGBgYFBQcFBQYFBQUFBAkFAwMDAwMDAwQDBAUFBgYEBgQFBQUFAgQABAQEBAQEBAMDAwMDAwMGBgYGBgQFBQUFBQQCBwUCBQUFBQUFBQUFBQICAgICBQYFBQUFBQUFBQUFBAUEBwQFBQUCAgYGBQUDBgYGBgYGBgYFBQUFAgICAgYGBgYGBgYGBgYFBQUFBQUFBQUFBQUFAgICAgUFBQUFBQUFBQUEBAYFBgUGBQYFBgUGBQYFBgYFBQUFBQUFBQUFBgUGBQYFBgUGBQICAgICAgICAgcEBQIGBAUCBQIFAwUDBgUGBQYFBQYFBgUGBQUDBQMFAwUFBQUFBQUFBQUFAwUDBQMGBQYFBgUGBQYFBgUIBwUEBQUEBQQFBAgHBgUFBQUFBQUFBQUFBQQEBAQCAgICBQUFBQUFBQUFBQUFBQUFBQUFBQQEBAQEBQUFBQUCAgICAgQFBAQEBAUFBQUFBQUFBQUFBQUFBQUFBQUFBQUHBQUFBQUGBQYCBgYGAwYFBQUGAgYIBgYGBQUGAgUFBQUDBQUFBQQEAwUFBQcFBQUCAgUGBgYGBQUFBggGBgYGBgUGBQUFBQUFBAQFBAUCAgIF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OfA6AjnwOeo56jnqOeo0rjnwNMw5zDnMOcw5zDiKNv42/jb+Nv42/jb+Nv40zDd6N3o3ejd6OBg4GDgYOBg4GDnMOcw5zDnMOcw2hDdcN1w3XDdcN1w3XDdcNYw1jDWMNYw4OjeIN4g3iDeIN4g5djl2Nv43XDb+N1w2/jdcNMw0zDTMNMw5zDd6NYw3ejWMN3o1jDd6NYw3ejWMOBg4OjgYOBg4GDgYOBg3uDgCOAI4AjgCOBg4OjgYODo4GDg6ODo5zDeIOcw3iDnMN4g4fDh8OHw4ijiKOIo5lDaEOXY2hDmyObI5sjoCOgI6CDnwOfA58DnwOfA58DnwOgI6AjoCOgI6AjnwOfA58DoCOeo0vDS8NLw0vDoCOgI6AjoINv43ejgYOBg5zDaENv43rjd6ObI4GDgYN7g4GDgYOcw4RDiKNoQ03jgYNoQ4OjeIOXY3iDd6NcY4GDgYN7g3uDVCNv43rjXGN3o4GDgYOcw4RDTMOIo03jdcNYw3iDhmOXY1PDWMNZY5djmUOZQ5lDaEOXY0xjTGNMY4GDg6Nv43XDd6NYw5WDl2NMw2hDl2OBg03jU8OBg2/jdcNv43XDd6NYw1jDWMNN41PDnMN4g3iDhmNUI5djVCOXY1Qjl2Nv43XDb+N1w2/jdcNv43XDb+N1w2/jdcNv43XDb+N1w2/jdcNv43XDb+N1w2/jdcN3o1jDd6NYw3ejWMN3o1jDd6NYw3ejWMN3o1jDd6NYw4GDgYOcw3iDnMN4g5zDeIOcw3iDnMN4g5zDeIOcw3iDeINoQ5djaEOXY2hDl2OIo1xjWWODo1oDXGN7g2hDgYODo2/jdcN3o4GDnMN4g4fDeuOGY5zDnMOBg4Oje4N7g4AjgYODo4GDg6Ocw4RDhmOHw4ijlYOXY5WDl2OZQ5sjnMOfA6AjnwOeo6CDnqOfA6AjoIAAIApAAEAAQAAAAGAAYAAQALAAwAAgATABMABAAlACoABQAsAC0ACwAvADYADQA4ADgAFQA6AD8AFgBFAEYAHABJAEoAHgBMAEwAIABPAE8AIQBRAFQAIgBWAFYAJgBYAFgAJwBaAF0AKABfAF8ALACKAIoALQCWAJYALgCdAJ0ALwCxALUAMAC3ALkANQC7ALsAOAC9AL4AOQDAAMEAOwDDAMUAPQDHAM4AQADSANIASADUAN4ASQDgAO8AVADxAPEAZAD2APgAZQD7APwAaAD+AQAAagEDAQUAbQEKAQoAcAENAQ0AcQEYARoAcgEiASIAdQEuATAAdgEzATUAeQE3ATcAfAE5ATkAfQE7ATsAfgFDAUQAfwFUAVQAgQFWAVYAggFYAVgAgwFcAV4AhAGEAYUAhwGHAYkAiQHYAdgAjAHaAdsAjQHdAd0AjwHgAeEAkAHrAe0AkgH/Af8AlQIOAhAAlgIwAjAAmQIzAjMAmgJFAkUAmwJHAkgAnAJ6AnsAngJ9An0AoAJ/ApQAoQKZAqAAtwKiAqUAvwKqAq8AwwK0ArwAyQK+Ar4A0gLAAsAA0wLCAsIA1ALEAsQA1QLGAs8A1gLYAtoA4ALcAtwA4wLeAt4A5ALgAuAA5QLiAuIA5gLnAucA5wLpAukA6ALrAusA6QLtAu0A6gLvAu8A6wLxAv0A7AL/Av8A+QMBAwEA+gMDAwMA+wMOAw4A/AMQAxAA/QMSAxIA/gMgAyAA/wMiAyUBAAMnAycBBAMpAykBBQMvAzgBBgNDA0cBEANNA08BFQNUA1QBGANlA2kBGQNtA28BHgN4A3gBIQOGA4sBIgOOA50BKAOgA6ABOAOkA6QBOQOmA6YBOgOqA6oBOwOtA64BPAOwA7EBPgOzA7kBQAO7A70BRwO/A8QBSgPGA8cBUAPJA8wBUgPSA9MBVgPVA9UBWAPXA9cBWQPZA9wBWgPfA+QBXgPmA+YBZAPqA+sBZQPwA/ABZwPyA/sBaAP+A/8BcgQBBAQBdAQLBAwBeAQQBBABegQSBBgBewQeBEYBggRIBEgBqwRKBFcBrARfBF8BugRwBHUBuwR3BHcBwQR7BHwBwgR/BH8BxASBBIIBxQSEBIQBxwSGBIYByASXBJsByQSdBJ0BzgSfBKABzwSiBKIB0QSmBKgB0gSqBKoB1QSsBK4B1gSwBLAB2QSyBLIB2gS0BLoB2wS8BLwB4gS/BL8B4wTCBMYB5ATIBMgB6QTKBMsB6gTPBM8B7ATSBNIB7QTYBNgB7gTdBN0B7wToBOgB8ATqBOoB8QTxBPEB8gT1BPUB8wALADj/2ADS/9gA1v/YATn/2AFF/9gDDv/YAxD/2AMS/9gDwf/YBHf/2AS//9gAGAA6ABQAOwASAD0AFgEZABQCmQAWAyAAEgMiABYDJAAWA4sAFgOaABYDnQAWA9MAEgPVABID1wASA9kAFgPqABQD8gAWBHAAFgRyABYEdAAWBIYAFgTCABQExAAUBMYAEgABABP/IADnABD/FgAS/xYAJf9WAC7++AA4ABQARf/eAEf/6wBI/+sASf/rAEv/6wBT/+sAVf/rAFb/5gBZ/+oAWv/oAF3/6ACU/+sAmf/rAJv/6gCy/1YAtP9WALv/6wC9/+gAyP/rAMn/6wDL/+oA0gAUANYAFAD3/+sBA//rAQ3/VgEY/+sBGv/oAR7/6wEi/+sBOQAUAUL/6wFFABQBYP/rAWH/6wFr/+sBhv8WAYr/FgGO/xYBj/8WAev/wAHt/8ACM//AAn//VgKA/1YCgf9WAoL/VgKD/1YChP9WAoX/VgKa/94Cm//eApz/3gKd/94Cnv/eAp//3gKg/94Cof/rAqL/6wKj/+sCpP/rAqX/6wKr/+sCrP/rAq3/6wKu/+sCr//rArD/6gKx/+oCsv/qArP/6gK0/+gCtf/oArb/VgK3/94CuP9WArn/3gK6/1YCu//eAr3/6wK//+sCwf/rAsP/6wLF/+sCx//rAsn/6wLL/+sCzf/rAs//6wLR/+sC0//rAtX/6wLX/+sC5f74Avn/6wL7/+sC/f/rAw4AFAMQABQDEgAUAxX/6gMX/+oDGf/qAxv/6gMd/+oDH//qAyP/6AMy/8ADM//AAzT/wAM1/8ADNv/AAzf/wAM4/8ADTf/AA07/wANP/8ADhv9WA47/VgOe/+sDov/qA6T/6wOm/+gDqf/qA6r/6wOr/+oDsv74A7b/VgPBABQDw//eA8T/6wPG/+sDyP/rA8n/6APL/+sD0v/oA9r/6APi/1YD4//eA+b/6wPr/+gD7P/rA/H/6wPz/+gD+P9WA/n/3gP6/1YD+//eA///6wQB/+sEAv/rBAz/6wQO/+sEEP/rBBT/6AQW/+gEGP/oBB3/6wQe/1YEH//eBCD/VgQh/94EIv9WBCP/3gQk/1YEJf/eBCb/VgQn/94EKP9WBCn/3gQq/1YEK//eBCz/VgQt/94ELv9WBC//3gQw/1YEMf/eBDL/VgQz/94ENP9WBDX/3gQ3/+sEOf/rBDv/6wQ9/+sEP//rBEH/6wRD/+sERf/rBEv/6wRN/+sET//rBFH/6wRT/+sEVf/rBFf/6wRZ/+sEW//rBF3/6wRf/+sEYf/rBGP/6gRl/+oEZ//qBGn/6gRr/+oEbf/qBG//6gRx/+gEc//oBHX/6AR3ABQEmf9WBJr/3gSc/+sEoP/rBKT/6gSp/+sEq//rBL8AFATD/+gExf/oBMv/wATS/8AE6v/AADMAOP/VADr/5AA7/+wAPf/dANL/1QDW/9UBGf/kATn/1QFF/9UB6wAOAe0ADgIzAA4Cmf/dAw7/1QMQ/9UDEv/VAyD/7AMi/90DJP/dAzIADgMzAA4DNAAOAzUADgM2AA4DNwAOAzgADgNNAA4DTgAOA08ADgOL/90Dmv/dA53/3QPB/9UD0//sA9X/7APX/+wD2f/dA+r/5APy/90EcP/dBHL/3QR0/90Ed//VBIb/3QS//9UEwv/kBMT/5ATG/+wEywAOBNIADgTqAA4AHQA4/7AAOv/tAD3/0ADS/7AA1v+wARn/7QE5/7ABRf+wApn/0AMO/7ADEP+wAxL/sAMi/9ADJP/QA4v/0AOa/9ADnf/QA8H/sAPZ/9AD6v/tA/L/0ARw/9AEcv/QBHT/0AR3/7AEhv/QBL//sATC/+0ExP/tABEALv/uADn/7gKV/+4Clv/uApf/7gKY/+4C5f/uAxT/7gMW/+4DGP/uAxr/7gMc/+4DHv/uA7L/7gRi/+4EZP/uBMH/7gBNAAYAEAALABAADQAUAEEAEgBH/+gASP/oAEn/6ABL/+gAVf/oAGEAEwCU/+gAmf/oALv/6ADI/+gAyf/oAPf/6AED/+gBHv/oASL/6AFC/+gBYP/oAWH/6AFr/+gBhAAQAYUAEAGHABABiAAQAYkAEAKh/+gCov/oAqP/6AKk/+gCpf/oAr3/6AK//+gCwf/oAsP/6ALF/+gCx//oAsn/6ALL/+gCzf/oAs//6ALR/+gC0//oAtX/6ALX/+gDnv/oA8T/6API/+gDy//oA9sAEAPcABAD3wAQA+b/6APs/+gD8f/oA///6AQB/+gEAv/oBA7/6AQd/+gEN//oBDn/6AQ7/+gEPf/oBD//6ARB/+gEQ//oBEX/6ARZ/+gEW//oBF3/6ARh/+gEnP/oBKn/6ASr/+gAQABH/+wASP/sAEn/7ABL/+wAVf/sAJT/7ACZ/+wAu//sAMj/7ADJ/+wA9//sAQP/7AEe/+wBIv/sAUL/7AFg/+wBYf/sAWv/7AKh/+wCov/sAqP/7AKk/+wCpf/sAr3/7AK//+wCwf/sAsP/7ALF/+wCx//sAsn/7ALL/+wCzf/sAs//7ALR/+wC0//sAtX/7ALX/+wDnv/sA8T/7API/+wDy//sA+b/7APs/+wD8f/sA///7AQB/+wEAv/sBA7/7AQd/+wEN//sBDn/7AQ7/+wEPf/sBD//7ARB/+wEQ//sBEX/7ARZ/+wEW//sBF3/7ARh/+wEnP/sBKn/7ASr/+wAGABT/+wBGP/sAqv/7AKs/+wCrf/sAq7/7AKv/+wC+f/sAvv/7AL9/+wDpP/sA6r/7APG/+wEDP/sBBD/7ARL/+wETf/sBE//7ARR/+wEU//sBFX/7ARX/+wEX//sBKD/7AAGABD/hAAS/4QBhv+EAYr/hAGO/4QBj/+EABEALv/sADn/7AKV/+wClv/sApf/7AKY/+wC5f/sAxT/7AMW/+wDGP/sAxr/7AMc/+wDHv/sA7L/7ARi/+wEZP/sBMH/7AAgAAb/8gAL//IAWv/zAF3/8wC9//MA9v/1ARr/8wGE//IBhf/yAYf/8gGI//IBif/yArT/8wK1//MDI//zA6b/8wPJ//MD0v/zA9r/8wPb//ID3P/yA9//8gPr//MD8//zBBT/8wQW//MEGP/zBHH/8wRz//MEdf/zBMP/8wTF//MAPwAn//MAK//zADP/8wA1//MAg//zAJP/8wCY//MAs//zAMQADQDT//MBCP/zARf/8wEb//MBHf/zAR//8wEh//MBQf/zAWr/8wJF//MCRv/zAkj/8wJJ//MChv/zApD/8wKR//MCkv/zApP/8wKU//MCvP/zAr7/8wLA//MCwv/zAtD/8wLS//MC1P/zAtb/8wL4//MC+v/zAvz/8wMt//MDiv/zA5f/8wO9//MDwP/zA+3/8wPw//MEC//zBA3/8wQP//MESv/zBEz/8wRO//MEUP/zBFL/8wRU//MEVv/zBFj/8wRa//MEXP/zBF7/8wRg//MEn//zBLj/8wBAACf/5gAr/+YAM//mADX/5gCD/+YAk//mAJj/5gCz/+YAuP/CAMQAEADT/+YBCP/mARf/5gEb/+YBHf/mAR//5gEh/+YBQf/mAWr/5gJF/+YCRv/mAkj/5gJJ/+YChv/mApD/5gKR/+YCkv/mApP/5gKU/+YCvP/mAr7/5gLA/+YCwv/mAtD/5gLS/+YC1P/mAtb/5gL4/+YC+v/mAvz/5gMt/+YDiv/mA5f/5gO9/+YDwP/mA+3/5gPw/+YEC//mBA3/5gQP/+YESv/mBEz/5gRO/+YEUP/mBFL/5gRU/+YEVv/mBFj/5gRa/+YEXP/mBF7/5gRg/+YEn//mBLj/5gA4ACX/5AA8/9IAPf/TALL/5AC0/+QAxP/iANr/0gEN/+QBM//SAUP/0gFd/9ICf//kAoD/5AKB/+QCgv/kAoP/5AKE/+QChf/kApn/0wK2/+QCuP/kArr/5AMi/9MDJP/TA4b/5AOL/9MDjv/kA5r/0wOb/9IDnf/TA7b/5APC/9ID2f/TA+L/5APy/9MD9f/SA/j/5AP6/+QEA//SBB7/5AQg/+QEIv/kBCT/5AQm/+QEKP/kBCr/5AQs/+QELv/kBDD/5AQy/+QENP/kBHD/0wRy/9MEdP/TBIb/0wSZ/+QAKAAQ/x4AEv8eACX/zQCy/80AtP/NAMf/8gEN/80Bhv8eAYr/HgGO/x4Bj/8eAn//zQKA/80Cgf/NAoL/zQKD/80ChP/NAoX/zQK2/80CuP/NArr/zQOG/80Djv/NA7b/zQPi/80D+P/NA/r/zQQe/80EIP/NBCL/zQQk/80EJv/NBCj/zQQq/80ELP/NBC7/zQQw/80EMv/NBDT/zQSZ/80AAQDEAA4AAgDK/+0A9v/AALoAR//cAEj/3ABJ/9wAS//cAFH/8wBS//MAU//WAFT/8wBV/9wAWf/dAFr/4QBd/+EAlP/cAJn/3ACb/90Au//cAL3/4QC+/+4Av//mAMH/8wDC/+sAw//pAMX/8ADG/+cAyP/cAMn/3ADK/+MAy//dAMz/zgDN/9QAzv/bAOz/8wDw//MA8f/zAPP/8wD0//MA9f/zAPf/3AD4//MA+v/zAPv/8wD+//MBAP/zAQP/3AEF//MBGP/WARr/4QEe/9wBIv/cASv/8wE2//MBPP/zAT7/8wFC/9wBU//zAVX/8wFX//MBXP/zAWD/3AFh/9wBa//cAqH/3AKi/9wCo//cAqT/3AKl/9wCqv/zAqv/1gKs/9YCrf/WAq7/1gKv/9YCsP/dArH/3QKy/90Cs//dArT/4QK1/+ECvf/cAr//3ALB/9wCw//cAsX/3ALH/9wCyf/cAsv/3ALN/9wCz//cAtH/3ALT/9wC1f/cAtf/3ALy//MC9P/zAvb/8wL3//MC+f/WAvv/1gL9/9YDFf/dAxf/3QMZ/90DG//dAx3/3QMf/90DI//h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A4v/0wOa/9MDm//0A53/0wOg/9EDpv/mA7X/7QPB/9IDwv/0A8X/0QPH/9EDyf/mA8r/7wPM/9ED0f/RA9L/5gPZ/9MD2v/mA9v/ygPc/8oD3//KA+H/0QPn/9ED6v/UA+v/5gPy/9MD8//mA/X/9AP2/+8EA//0BAT/7wQI/9EECv/RBBP/7QQU/+YEFf/tBBb/5gQX/+0EGP/mBBn/4QQc/9EEcP/TBHH/5gRy/9MEc//mBHT/0wR1/+YEd//SBHn/4QR8/9EEhv/TBJj/0QS1/9EEt//RBL//0gTC/9QEw//mBMT/1ATF/+YAKAA4/74AWv/vAF3/7wC9/+8A0v++ANb/vgDm/8kA9v/fAQn/7QEa/+8BIP/rATn/vgE6/98BRf++AUz/6QFj//UBbf/gArT/7wK1/+8DDv++AxD/vgMS/74DI//vA6b/7wPB/74Dyf/vA9L/7wPa/+8D6//vA/P/7wQU/+8EFv/vBBj/7wRx/+8Ec//vBHX/7wR3/74Ev/++BMP/7wTF/+8APwA4/+YAOv/nADz/8gA9/+cAXP/xANL/5gDW/+YA2v/yAN7/7gDh/+gA5v/mAO7/8QD2/9ABGf/nATP/8gE0//EBOf/mATr/zgFD//IBRP/xAUX/5gFH/+gBSf/oAV3/8gFe//EBYv/nAWT/7QFs/+YBbf/QApn/5wMO/+YDEP/mAxL/5gMi/+cDJP/nA4v/5wOa/+cDm//yA53/5wO1/+4Dwf/mA8L/8gPK//ED2f/nA+r/5wPy/+cD9f/yA/b/8QQD//IEBP/xBBP/7gQV/+4EF//uBBn/6ARw/+cEcv/nBHT/5wR3/+YEef/oBIb/5wS//+YEwv/nBMT/5wCYACUAEAAn/+gAK//oADP/6AA1/+gAOP/gADr/4AA9/98Ag//oAJP/6ACY/+gAsgAQALP/6AC0ABAA0v/gANP/6ADUABAA1v/gANkAFADdABAA4f/hAOb/4ADtABMA8gAQAPn/4AEEABABCP/oAQ0AEAEX/+gBGf/gARv/6AEd/+gBH//oASH/6AE5/+ABQf/oAUX/4AFH/+EBSP/gAUn/4QFK/+ABTf/hAVAAEAFRABABWP/pAWL/3wFk/94BZgAQAWr/6AFs/98Bbv/yAW8AEAFwABACRf/oAkb/6AJI/+gCSf/oAn8AEAKAABACgQAQAoIAEAKD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AAAAAAAAAAAAAwADAAQAAwABAAAADgAAAAUACQAAABUACQAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgABAAAAAAAAAAIAAQAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAIABgAAAAAAAAAAAAAAAAABAAAACQAAAAAAAAADAAAAAAAAAAAAAAAAAAEAAQAAAAUAAAAAAAAAAAAAAAAACwACABkAAAALAAAAAAAAABEAAAAAABkAIgAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAVAAAAAwADABsAAwADAAMAAAABAAMAIQADAAMAAAAAAAMAAAADAAAAAAABABsAAwAAAAAAAgAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAgAEAB0ACQACAAAAAgABAAIAAAACAAEAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAARABUAAAADAAAAAAALAAAAAAADAAAAAwAAAAAAAgABABEAFQALAAAAIAAhAAAAAAAAAAAAAAAAAAAAGQAbAAAAAwAAAAMAAAADAAAAAAAAAAAAAwARABUAAAABAAEAAAAAAAAAAAAZAAAAAAAAAAIAAQAAAAAAAAAZABsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAB8AAAAUABQAGgAUABQAFAAaAAAAAAAAABoAGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcAHAAkAAAAEgAYAB4AAAAIAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAA0ACAANAAAAAAAAAAAAAAAAABgACAAAAAAAGAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAGAAIABcAHAAYAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAA0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgAAAAIAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAABgAGAAYABgAGAAYABgACAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgACAAIAAgAKAAoACgAKAAwABwAHAAcABwAHAAcABwABAAEAAQABAAEAAAAAAAAAAAADAAQABAAEAAQABAAFAAUABQAFAAkACQAGAAcABgAHAAYABwACAAEAAgABAAIAAQACAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAgABAAIAAQACAAEAAgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAwAAAAMAAwACAAQAAgAEAAIABAAAAAAAAAAAAAAAAAAQAA4AEAAOABAADgAQAA4AEAAOAAsAAAALAAAACwAAAAoABQAKAAUACgAFAAoABQAKAAUACgAFABYAAAAMAAkADAATAA8AEwAPABMADwAAAAAAAgAAAAAAAAAAAA0ADQANAA0ADQANAA0ACAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgACAAIAAgAEgASABIAEgAXAA0ADQANAAgACAAIAAgAAAAAAAAAAAAAAAAACAAIAAgACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgACAAAAAAAAAAeAB4AHgAeAAAAGAAAABIAEgASABIAEgASACQAFwAXAAAAAAAAAAYAAAAAAAAAAgAMAAAAAAAGAAAAAAATAAAAAAAAAAAAAAACAAAAAAAMABEAAAAMAAEAAAADAAAABQAAAAQAAAAJAAAAAAAFAAQABQAAAAAAAAAAAAAAAAAjAAAAAAAiAAYAAAAAAAAAAAAAAAAAAgAAAAAAAgALABEABwABAAMABAADAAEACQAVAAEAAwAOAAAAAAAA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BPcE+QT6BPwCGgT9BPsCDAISBQsFDAABAPoACAAKABQAFQAWABcAGAAZABoAGwAcAB0AJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQA+AGUAZwCBAIMAhACMAI8AkQCTALEAsgCzALQAtQC2ALcAuAC5ALoA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoAOkBLwEzATUBNwE5ATsBQQFDAUUBSQFLAUwBWAFZAZcBnQGiAaUCegJ7An0CfwKAAoECggKDAoQChQKGAocCiAKJAooCiwKMAo0CjgKPApACkQKSApMClAKVApYClwKYApkCtgK4AroCvAK+AsACwgLEAsYCyALKAswCzgLQAtIC1ALWAtgC2gLcAt4C4ALiAuMC5QLnAukC6wLtAu8C8QLzAvUC+AL6AvwC/gMAAwIDBAMGAwgDCgMMAw4DEAMSAxQDFgMYAxoDHAMeAyADIgMkAyUDJwMpAysDLQOGA4cDiAOJA4oDiwOMA44DjwOQA5EDkgOTA5QDlQOWA5cDmAOZA5oDmwOcA50DrQOuA68DsAOxA7IDswO0A7UDtgO3A7gDuQO6A7sDvAO9A74DvwPAA8EDwgPTA9UD1wPZA+4D8APyBAcEDQQTBH0EggSGBQcFCQABAAAAAQAIAAIB3ADrAnECMwIyAjECMAIoAeYB5QHkAeMB4gHhAeAB3wHeAd0B3AHbAdoB2QHYAdcB1gHVAdQB0wHSAmQCcwMwAnUCdAMvAeMCcgJ3AlIE0gTTAeoB6wTUBNUE1gHsBNcB7QHuAe8E3AHwAfAE3QTeAfEB8gHzAfoE6wTsAfsB/AH9Af4B/wIABO8E8ATyBPUE/gICAgMCBAIFAgYCBwIIAgkCCgILAfQB9QH2AfcB+AH5AjsCDQIOAg8CEAT4AhECEwIUAhUCFwIZAnYDMQMyAzMDNAM1AzYDNwM4AzkDOgM7AzwDPQM+Az8DQANBA0IDQwNEA0UDRgNHA0gDSQNKA0sDTAOCA00DTgNPA1ADUQNSA1MDVANVA1YDVwNYA1kDWgNbA1wDXQNeA18DYANhA2IE/wNkA2UDZgNnA2gDaQNqA2sDbANtA24DbwNwA3EDcgNzA3QDdQUCA3YDdwN5A3gDegN7A3wDfQN+A38DgAOBA4MDhAOFBQAFAQTLBMwEzQTOBNgE2wTZBNoE3wTgBOEEzwTQBNEE6gTtBO4E8QTzBPQCAQT2BOIE4wTkBOUE5gTnBOgE6QUDBQQFBQUGBPcE+QT6AhgE/AIaBP0E+wIWAgwCEgULBQwAAQDrAAoARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAIUAhgCHAIkAigCLAI0AkACSAJQAuwC8AL0AvgC/AMAAwQDCAMMAxADFAMYAxwDIAMkAygDLAMwAzQDOAOoA6wDsAO0A7gDvAPAA8QDyAPMA9AD1APYA9wD4APkA+gD7APwA/QD+AP8BAAEBAQIBAwEEAQUBBgEHATABNAE2ATgBOgE8AUIBRAFGAUoBTQFaAnwCfgKaApsCnAKdAp4CnwKgAqECogKjAqQCpQKmAqcCqAKpAqoCqwKsAq0CrgKvArACsQKyArMCtAK1ArcCuQK7Ar0CvwLBAsMCxQLHAskCywLNAs8C0QLTAtUC1wLZAtsC3QLfAuEC5ALmAugC6gLsAu4C8ALyAvQC9gL5AvsC/QL/AwEDAwMFAwcDCQMLAw0DDwMRAxMDFQMXAxkDGwMdAx8DIQMjAyYDKAMqAywDLgOeA58DoAOhA6MDpAOlA6YDpwOoA6kDqgOrA6wDwwPEA8UDxgPHA8gDyQPKA8sDzAPNA84DzwPQA9ED0gPUA9YD2APaA+8D8QPzBAEECAQOBBQEfgR/BIMEhwUIBQoABgAAAAYAEgAqAEIAWgByAIoAAwAAAAEAEgABAJAAAQAAAAMAAQABAE0AAwAAAAEAEgABAHgAAQAAAAMAAQABAE4AAwAAAAEAEgABAGAAAQAAAAMAAQABAuEAAwAAAAEAEgABAEgAAQAAAAMAAQABA84AAwAAAAEAEgABADAAAQAAAAMAAQABA9AAAwAAAAEAEgABABgAAQAAAAMAAQABBEkAAgACAKgArAAAASQBJwAFAAEAAAABAAgAAgASAAYCYQJfAmICYwJgBQ0AAQAGAE0ATgLhA84D0ARJAAQAAAABAAgAAQYyADYAcgCkAK4AuADKAPwBDgEYAUoBZAF+AZABugH2AgACIgI8Ak4CigKcArYC4ALyAyQDLgM4A0oDfAOGA5ADmgO0A84D4AQKBDwERgRoBIIElATGBNgE8gUcBS4FOAVCBUwFVgWABaoF1AX+BigABgAOABQAGgAgACYALAKAAAIAqQQeAAIArQJ/AAIAqAQgAAIAqwKCAAIAqgSZAAIArAABAAQEpgACAK0AAQAEArwAAgCpAAIABgAMBKoAAgG6BKgAAgCtAAYADgAUABoAIAAmACwCiAACAKkENgACAK0ChwACAKgEOAACAKsEOgACAKoEmwACAKwAAgAGAAwElQACAKkC1gACAboAAQAEBKwAAgCtAAYADgAUABoAIAAmACwCjAACAKkESAACAK0CiwACAKgERgACAKsC2gACAKoEnQACAKwAAwAIAA4AFASuAAIAqQLnAAIBugSwAAIArQADAAgADgAUAukAAgCpAusAAgG6BLIAAgCtAAIABgAMA+AAAgCpBLQAAgCtAAUADAASABgAHgAkAvEAAgCpAvMAAgG6BLYAAgCtBJcAAgCoAo8AAgCqAAcAEAAYAB4AJAAqADAANgS4AAMAqgCpApEAAgCpBEoAAgCtApAAAgCoBEwAAgCrApMAAgCqBJ8AAgCsAAEABAS5AAIAqQAEAAoAEAAWABwC/gACAKkDAAACAboEuwACAK0EoQACAKwAAwAIAA4AFAMEAAIAqQMKAAIBugS9AAIArQACAAYADAMOAAIBugS/AAIArQAHABAAGAAeACQAKgAwADYEwQADAKoAqQKWAAIAqQRiAAIArQKVAAIAqARkAAIAqwMUAAIAqgSjAAIArAACAAYADATEAAIArQTCAAIAqgADAAgADgAUA9UAAgCpBMYAAgCtA9MAAgCoAAUADAASABgAHgAkApkAAgCpBHAAAgCtA9kAAgCoBHIAAgCrBHQAAgCqAAIABgAMAyUAAgCpBMgAAgCtAAYADgAUABoAIAAmACwCmwACAKkEHwACAK0CmgACAKgEIQACAKsCnQACAKoEmgACAKwAAQAEBKcAAgCtAAEABAK9AAIAqQACAAYADASrAAIBugSpAAIArQAGAA4AFAAaACAAJgAsAqMAAgCpBDcAAgCtAqIAAgCoBDkAAgCrBDsAAgCqBJwAAgCsAAEABASWAAIAqQABAAQErQACAK0AAQAEBEkAAgCtAAMACAAOABQErwACAKkC6AACAboEsQACAK0AAwAIAA4AFALqAAIAqQLsAAIBugSzAAIArQACAAYADAPhAAIAqQS1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) -} - -@font-face { - font-family: Roboto Mono; - font-weight: 400; - src: url(data:font/ttf;base64,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fIV8jXyVfKB8q3y2fMF8zHzYfOR9XH1kfXB9eH2AfYx9mH2gfah9sH24fcR9zH3Ufdx95H3sffR9/H4Efgx+FH4cfid+L343foV+jX6VfqB+q36zfrt+xn7Oftl+5H7xfvx/BH8Qfxx/J38yfz5/Sn9Wf2F/bX91f31/iX+Vf6B/q3+2f8F/yX/Rf9l/5X/wf/iABIAPgBuAJoAugDaAQoBNgFmAYYBsgHiAg4CPgJqApoCxgL2AyIDUgN+A54DvgPuBBoESgR2BKYE0gUCBS4FXgWOBb4F6gYaBkYGdgamBsYG9gcmB1YHhge2B+YIFghCCHIIngjOCPoJKglWCZYJ1goGCjIKYgqOCr4K6gsaC0YLhgvCC/IMIgxSDIIMsgziDRINPg1uDZoNyg32DiYOUg6SDs4O/g8uD14Pjg++D+4QHhBOEH4QqhDaEQYRNhFiEZIRvhH+EjoSahKWEsYS8hMiE1ITghOyE+IUEhRCFHIUohTSFQIVLhVeFYoVuhXqFhoWShZ6FqoW2hcKFzoXaheaF8oYBhg2GGYYlhjGGPYZJhlWGYYZthnmGhYaRhp2GqYa1hsGGzYbZhuGHHodbh5iHsofMh/KIFogmiDWIQYhNiFmIZYhxiH2IoYjDiOqJEYkZiSYAAQAAAAMAALCPXPRfDzz1AAsIAAAAAADE8BEuAAAAANrYP6v8Bf3VBkcIYgAAAAkAAgAAAAAAAATNAAAAAABRAKwAawCbALYAvwBkAI0ArgBiAKwAxgCUAI8AagC/AF4AtQB2AEwAiwBHAEkAVwA9AHIAnACvAI8AiwCHAJgAjACuAMsA0wCwAMsAXQCuAHoArQCMAUkArwCOALQAYgAwAG4ARACgAJEA0ABVAF4ASwC7AI0AcACxAJUBggE8AUMBHAEQACQAMAAmACAAKwBPAC4ASQCoAK0AugCpALEAogCTAHEAIQCgABEAaQB/AGcB5gHyAL8AzAFiAfACIgHmAQkB+AGaAJsA2gBKAE8B7gFiAewBzQG8AUkBLQEvAe4BYgFlAUABqgGVAUMBQwGMAYwAdwCpAJwAtQBzAK0AqQCNAKoAsgC7AMIAvQD8AOcBKwAsADYCHAH/AHcAeQBaAFcAZwFpAKAAPQBrAEAAVwDTAOcAMABRAFEAUQBRAFEAUQBRAFEAUQBRACAAawBrAGsAawCb/8UAtgC2ALYAtgC2ALYAtgC2AK8Atv/FAGQAZABkABgAjQCuAK4ArgCuAK4ArgCuAK4ArgBiAKwAxgDGAMYAxgA6AI8AjwCPAI8AagBqAGoAagBqAGMAagBqAEcARwBqALUAtQC1AHYAdgB2AHYATABMAIsAiwCLAIsAiwCLAIsAiwCLAIsAiwBJAEkASQBJAD0APQA9AD0AcgByAHIAnACcAJwAnACcAJwAnACcAJwAnAArAI8AjwCPAI8AZAB8AIcAhwCHAIcAhwCHAIcAhwC4AIcAjACMAIwAC//nAMsAywDLAMsAywDLAMsAywCwALAAywCZAMsAhQDLAK4ArgCuAK4AegB6AHoAegB6AHcAegB6AHoAegB6AUkBFAEQAK8ArwCvAK8AjgB/ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAAwADAAMAAwAEQARABEAEQAoACgAKABnwGaAMEAigEBATsB8gEfAZoA9gEw/ScBzQGOAS4AAADUALwA8QDLAIAAUAHIALABrfzK/Wj8iP1Z/AUCKQETAjAAtQAuAGoANgCRAKIAcABFAGUAYQCBAK4ARwB4AIsAdQCkALkAuAA5AK8AWQClAHgAbQCtAJ4AbgBhAE8AmAA2AC4AKgCBAB4AgwBDAKIAogBGAB0AWQCiAC8AKwCmAKsAfQB9ADIAkACoAHIAdwBBAIEApAC3ADYAEQCHAKUApAA3AIkApQClAGgAegCqAI0AgQB2ADkAkAClAIEAcQBP/+kAjwAmAIIAHAClAGsAXwAcAH0AmwAnAFcAcQBwAFUAaQBQAFEAygDeAGMAXQAaAFEARQA3AGoAegBNAGcAcQBfAJcAvwB2ANEA/AHDAjz+q/60AL8ArQC2ALYAuQC4AK4AowAtADgAcgBuAG0AdABoAFwAOQA0AKsAkgDjACYAJgDIALQAtgCzAFoAlACJAEIAdABhAE0AZQA3AFAAswDQABQALwBvAHUAjgCgAEwASQBsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKYBzwFcAQ8BSwB/AEkA3QB5AJkAUAAzACQAQQB+AKcAMwA5ADUA+ACOAAAAXAAPAREA/AAQAQsBPgH5ADYA0ABuALcAyADnAHwAmwDZAJYAtADRAJsAwgCCAF4AkACKAF0AtQBWAC8AYABNALkBUgFCATUB0QH1AXQCBgFgAMwAqQDS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AGQBZgBAAEQBbABGAEUARwBeAKIAngCgAKcAoQClAEgAqwC1AK8AsgCzAMQAvwDBAMIAuQDSANcA0wDVAN0A1gB/ANsA6wDnAOkA6gD2AE0AUAEBAP0A/wEGAQABBABJAQoBFAEOAREBEgEhAR0BHwEgAEwBLwE0ATABMgE6ATMAgAE4AUgBRAFGAUcBUwBOAVUAowECAJ8A/gCkAQMAqQEIAKwBCwJ1AnYAqgEJAK0BDACuAQ0AtgEVALABDwC0ARMAuAEXALEBEAC7ARkAugEYAncCeAC8ARoAvgEcAL0BGwDHASQAxQEiAMABHgDGASMAwwFtAW4BbwDIASUAyQEmAE8AygEnAMwBKQDLASgAzQEqAM4BKwDPASwA0QEuANABLQJ5ALcBFgDaATcA1AExANkBNgBKAEsA3gE7AOABPQDfATwA4QE+AOQBQQDjAUAA4gE/An4CgADmAUMA5QFCAPEBTgDuAUsA6AFFAPABTQDtAUoA7wFMAPMBUAD3AVQA+AD6AVcA/AFZAPsBWAFwANgBNQDsAUkApgEFAKgBBwDcATkBXAFkAV8BYAFiAWcBXQFjAXgBeQLUAXoC1QLWAtcBewF8At4C3wLgAX0C4QLiAX4C4wLkAX8C5QGAAuYBgQLnAugBggLpAYMBhALqAusC7ALtAu4C7wLwAvEBjgLzAvQBjwLyAZABkQGSAZMBlAGVAZYC9QGXAZgDKgL7AZwC/AGdAv0C/gL/AwABngGfAaADAgMrAwMBoQMEAaIDBQMGAaMDBwGkAaUBpgMIAwEBpwMJAwoDCwMMAw0DDgMPAagDEAMRAxIBswG0AbUBtgMTAbcBuAG5AxQBugG7AbwBvQMVAb4DFgMXAb8DGAHAAxkDLAMaAcsDGwHMAxwDHQMeAx8BzQHOAc8DIAMtAyEB0AHRAdID1AMuAy8B4AHhAeIB4wMwAzEB8wH0A9kD2gPTA9IB9QH2AfcB+APVA9YB+QH6A80DzgMyAzMDvwPAAfsB/APXA9gB/QH+A8EDwgH/AgACAQICAgMCBAM0AzUDwwPEAzYDNwPhA+IDxQPGAgUCBgPHA8gCBwIIAgkD0QIKAgsDzwPQAzgDOQM6AgwCDQPfA+ACDgIPA9sD3APJA8oD3QPeAhADRQNEA0YDRwNIA0kDSgIRAhIDywPMA18DYAITAhQDYQNiA+MD5AIVA2MD5QNkA2UA9QFSAPIBTwD0AVEA+QFWAGgAaQPmAjEAbABtAG4CMgBvAHAAcQCQAJEAZQIzAGMDvgI2AkEAfbgB/4WwBI0AAAAAEQDSAAMAAQQJAAAAtAAAAAMAAQQJAAEAFgC0AAMAAQQJAAIADgDKAAMAAQQJAAMAOgDYAAMAAQQJAAQAJgESAAMAAQQJAAUAGgE4AAMAAQQJAAYAJAFSAAMAAQQJAAcASgF2AAMAAQQJAAkADAHAAAMAAQQJAAsAFAHMAAMAAQQJAAwAJgHgAAMAAQQJAA0AXAIGAAMAAQQJAA4AVAJiAAMAAQQJAQAADAK2AAMAAQQJAQsADALCAAMAAQQJAQ4ADgDKAAMAAQQJAREADALOAEMAbwBwAHkAcgBpAGcAaAB0ACAAMgAwADEANQAgAFQAaABlACAAUgBvAGIAbwB0AG8AIABNAG8AbgBvACAAUAByAG8AagBlAGMAdAAgAEEAdQB0AGgAbwByAHMAIAAoAGgAdAB0AHAAcwA6AC8ALwBnAGkAdABoAHUAYgAuAGMAbwBtAC8AZwBvAG8AZwBsAGUAZgBvAG4AdABzAC8AcgBvAGIAbwB0AG8AbQBvAG4AbwApAFIAbwBiAG8AdABvACAATQBvAG4AbwBSAGUAZwB1AGwAYQByADMALgAwADAAMAA7AEcATwBPAEcAOwBSAG8AYgBvAHQAbwBNAG8AbgBvAC0AUgBlAGcAdQBsAGEAcgBSAG8AYgBvAHQAbwAgAE0AbwBuAG8AIABSAGUAZwB1AGwAYQByAFYAZQByAHMAaQBvAG4AIAAzAC4AMAAwADAAUgBvAGIAbwB0AG8ATQBvAG4AbwAtAFIAZQBnAHUAbABhAHIAUgBvAGIAbwB0AG8AIABNAG8AbgBvACAAaQBzACAAYQAgAHQAcgBhAGQAZQBtAGEAcgBrACAAbwBmACAARwBvAG8AZwBsAGUALgBHAG8AbwBnAGwAZQBHAG8AbwBnAGwAZQAuAGMAbwBtAEMAaAByAGkAcwB0AGkAYQBuACAAUgBvAGIAZQByAHQAcwBvAG4ATABpAGMAZQBuAHMAZQBkACAAdQBuAGQAZQByACAAdABoAGUAIABBAHAAYQBjAGgAZQAgAEwAaQBjAGUAbgBzAGUALAAgAFYAZQByAHMAaQBvAG4AIAAyAC4AMABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBwAGEAYwBoAGUALgBvAHIAZwAvAGwAaQBjAGUAbgBzAGUAcwAvAEwASQBDAEUATgBTAEUALQAyAC4AMABXAGUAaQBnAGgAdABJAHQAYQBsAGkAYwBOAG8AcgBtAGEAbAACAAAAAAAA/2oAZAAAAAEAAAAAAAAAAAAAAAAAAAAAA+cAAAADACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQBEAEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AEwAUABUAFgAXABgAGQAaABsAHADxAPIA8wCdAJ4A9AD1APYAkACgALAAsQDqAO0A7gECAIkBAwAHAIQAhQCWAKYA9wEEAQUAvQAEAKMAIgCiAA8AEQAdAB4AqwDDAIcAQgAQALIAswAKAAUAtgC3AMQAtAC1AMUBBgEHAAsADAA+AEAAXgBgAL4AvwAOAO8AkwDwALgAIACPAKcAHwAhAJQAlQCkABIAPwC8AAgAxgBfAOgAggDCAIsAigCMAIMADQAGAAkAIwCGAIgAQQBhAMkBCADHAGIArQEJAQoAYwELAK4BDAD9AP8AZAENAQ4BDwBlARABEQDIAMoBEgDLARMBFAEVAOkA+AEWARcBGAEZAMwBGgDNAM4A+gDPARsBHAEdAR4BHwEgASEBIgEjAOIBJAElASYAZgDQAScA0QBnANMBKAEpASoAkQErAK8BLAEtAS4BLwDkAPsBMAExATIA1AEzANUAaADWATQBNQE2ATcBOAE5AToBOwE8AT0A6wE+ALsBPwFAAOYBQQBpAUIAawBsAGoBQwFEAG4BRQBtAUYA/gEAAG8BRwFIAQEAcAFJAUoAcgBzAUsAcQFMAU0BTgD5AU8BUAFRAVIAdAFTAHYAdwB1AVQBVQFWAVcBWAFZAVoBWwFcAOMBXQFeAV8AeAB5AWAAewB8AHoBYQFiAWMAoQFkAH0BZQFmAWcBaADlAPwBaQFqAWsAfgFsAIAAgQB/AW0BbgFvAXABcQFyAXMBdAF1AXYA7AF3ALoBeAF5AOcBegBDAI0A2ADZANoA2wDcAI4A3QDfAOEBewDeAOABfAACAKkAlwCqANcBfQF+AX8BgAGBAYIBgwGEAYUBhgGHAYgBiQGKAKgBiwGMAY0BjgGPAZABkQCfAZIBkwGUAZUBlgGXAZgBmQGaAZsBnACbAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0BzgHPAdAB0QHSAdMB1AHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gHzAfQB9QH2AfcB+AH5AfoB+wH8Af0B/gH/AgACAQICAgMCBAIFAgYCBwIIAgkCCgILAgwCDQIOAg8CEAIRAhICEwIUAhUCFgIXAhgCGQIaAhsCHAIdAh4CHwIgAiECIgIjAiQCJQImAicCKAIpAioCKwIsAi0CLgIvAjACMQIyAjMCNAI1AjYCNwI4AjkCOgI7AjwCPQI+Aj8CQAJBAkICQwJEAkUCRgJHAkgCSQJKAJgAmgCZAKUAkgCcALkCSwJMAk0CTgJPAlACUQJSAlMCVAJVAlYCVwJYAlkCWgJbAlwCXQJeAl8CYAJhAmICYwJkAmUCZgJnAmgCaQJqAmsCbAJtAm4CbwJwAnECcgJzAnQCdQJ2AncArAJ4AnkCegJ7AnwCfQJ+An8CgAKBAoICgwKEAoUChgKHAogCiQKKAosCjAKNAo4CjwKQApECkgKTApQClQKWApcCmAKZApoCmwKcAp0CngKfAqACoQKiAqMCpAKlAqYCpwKoAqkCqgKrAqwCrQKuAq8CsAKxArICswK0ArUCtgK3ArgCuQK6ArsCvAK9Ar4CvwLAAsECwgLDAsQCxQLGAscCyALJAsoCywLMAs0CzgLPAtAC0QLSAtMC1ALVAtYC1wLYAtkC2gLbAtwC3QLeAt8C4ALhAuIC4wLkAuUC5gLnAugC6QLqAusC7ALtAu4C7wLwAvEC8gLzAvQC9QL2AvcC+AL5AvoC+wL8Av0C/gL/AwADAQMCAwMDBAMFAwYDBwMIAwkDCgMLAwwDDQMOAw8DEAMRAxIDEwMUAxUDFgMXAxgDGQMaAxsDHAMdAx4DHwMgAyEDIgMjAyQDJQMmAycDKAMpAyoDKwMsAy0DLgMvAzADMQMyAzMDNAM1AzYDNwM4AzkDOgM7AzwDPQM+Az8DQANBA0IDQwNEA0UDRgNHA0gDSQNKA0sDTANNA04DTwNQA1EDUgNTA1QDVQNWA1cDWANZA1oDWwNcA10DXgNfA2ADYQNiA2MDZANlA2YDZwNoA2kDagNrA2wDbQNuA28DcANxA3IDcwN0A3UDdgN3A3gDeQN6A3sDfAN9A34DfwOAA4EDggODA4QDhQOGA4cDiAOJA4oDiwOMA40DjgOPA5ADkQOSA5MDlAOVA5YDlwOYA5kDmgObA5wDnQOeA58DoAOhA6IDowOkA6UDpgOnA6gDqQOqA6sDrAOtA64DrwOwA7EDsgOzA7QDtQO2A7cDuAO5A7oDuwO8A70DvgO/A8ADwQPCA8MDxAPFA8YDxwPIA8kDygPLA8wDzQPOA88D0APRA9ID0wPUA9UD1gPXA9gD2QPaA9sD3APdA94D3wPgA+ED4gPjA+QD5QPmA+cD6APpA+oMa2dyZWVubGFuZGljBXNjaHdhBGxpcmEGcGVzZXRhBm1pbnV0ZQZzZWNvbmQGQWJyZXZlB0FtYWNyb24HQW9nb25lawpBcmluZ2FjdXRlB0FFYWN1dGULQ2NpcmN1bWZsZXgGRGNhcm9uBkRjcm9hdAZFYnJldmUGRWNhcm9uCkVkb3RhY2NlbnQHRW1hY3JvbgNFbmcHRW9nb25lawtHY2lyY3VtZmxleAxHY29tbWFhY2NlbnQESGJhcgtIY2lyY3VtZmxleAZJYnJldmUHSW1hY3JvbgdJb2dvbmVrBkl0aWxkZQtKY2lyY3VtZmxleAxLY29tbWFhY2NlbnQGTGFjdXRlBkxjYXJvbgxMY29tbWFhY2NlbnQETGRvdAZOYWN1dGUGTmNhcm9uDE5jb21tYWFjY2VudAZPYnJldmUFT2hvcm4NT2h1bmdhcnVtbGF1dAdPbWFjcm9uC09zbGFzaGFjdXRlBlJhY3V0ZQZSY2Fyb24MUmNvbW1hYWNjZW50BlNhY3V0ZQtTY2lyY3VtZmxleARUYmFyBlRjYXJvbgZVYnJldmUFVWhvcm4NVWh1bmdhcnVtbGF1dAdVbWFjcm9uB1VvZ29uZWsFVXJpbmcGVXRpbGRlBldhY3V0ZQtXY2lyY3VtZmxleAlXZGllcmVzaXMGV2dyYXZlC1ljaXJjdW1mbGV4BllncmF2ZQZaYWN1dGUKWmRvdGFjY2VudAZhYnJldmUHYW1hY3Jvbgdhb2dvbmVrCmFyaW5nYWN1dGUHYWVhY3V0ZQtjY2lyY3VtZmxleAZkY2Fyb24GZWJyZXZlBmVjYXJvbgplZG90YWNjZW50B2VtYWNyb24DZW5nB2VvZ29uZWsLZ2NpcmN1bWZsZXgMZ2NvbW1hYWNjZW50BGhiYXILaGNpcmN1bWZsZXgGaWJyZXZlB2ltYWNyb24HaW9nb25lawZpdGlsZGULamNpcmN1bWZsZXgMa2NvbW1hYWNjZW50BmxhY3V0ZQZsY2Fyb24MbGNvbW1hYWNjZW50BGxkb3QGbmFjdXRlBm5jYXJvbgxuY29tbWFhY2NlbnQGb2JyZXZlBW9ob3JuDW9odW5nYXJ1bWxhdXQHb21hY3Jvbgtvc2xhc2hhY3V0ZQZyYWN1dGUGcmNhcm9uDHJjb21tYWFjY2VudAZzYWN1dGULc2NpcmN1bWZsZXgEdGJhcgZ0Y2Fyb24GdWJyZXZlBXVob3JuDXVodW5nYXJ1bWxhdXQHdW1hY3Jvbgd1b2dvbmVrBXVyaW5nBnV0aWxkZQZ3YWN1dGULd2NpcmN1bWZsZXgJd2RpZXJlc2lzBndncmF2ZQt5Y2lyY3VtZmxleAZ5Z3JhdmUGemFjdXRlCnpkb3RhY2NlbnQIZG90YmVsb3cLY29tbWFhY2NlbnQCSUoCaWoFbG9uZ3MHdW5pMDIzNwd1bmkwMkYzCWdyYXZlY29tYglhY3V0ZWNvbWIJdGlsZGVjb21iBGhvb2sHdW5pMDMwRgV0b25vcw1kaWVyZXNpc3Rvbm9zCWFub3RlbGVpYQVHYW1tYQVUaGV0YQZMYW1iZGECWGkCUGkFU2lnbWEDUGhpA1BzaQVhbHBoYQRiZXRhBWdhbW1hBWRlbHRhB2Vwc2lsb24EemV0YQNldGEFdGhldGEEaW90YQZsYW1iZGECeGkDcmhvBnNpZ21hMQVzaWdtYQN0YXUHdXBzaWxvbgNwaGkDcHNpBW9tZWdhB3VuaTAzRDEHdW5pMDNEMgd1bmkwM0Q2B3VuaTA0MDIHdW5pMDQwNAd1bmkwNDA5B3VuaTA0MEEHdW5pMDQwQgd1bmkwNDBGB3VuaTA0MTEHdW5pMDQxNAd1bmkwNDE2B3VuaTA0MTcHdW5pMDQxOAd1bmkwNDFCB3VuaTA0MjMHdW5pMDQyNgd1bmkwNDI3B3VuaTA0MjgHdW5pMDQyOQd1bmkwNDJBB3VuaTA0MkIHdW5pMDQyQwd1bmkwNDJEB3VuaTA0MkUHdW5pMDQyRgd1bmkwNDMxB3VuaTA0MzIHdW5pMDQzMwd1bmkwNDM0B3VuaTA0MzYHdW5pMDQzNwd1bmkwNDM4B3VuaTA0M0EHdW5pMDQzQgd1bmkwNDNDB3VuaTA0M0QHdW5pMDQzRgd1bmkwNDQyB3VuaTA0NDQHdW5pMDQ0Ngd1bmkwNDQ3B3VuaTA0NDgHdW5pMDQ0OQd1bmkwNDRBB3VuaTA0NEIHdW5pMDQ0Qwd1bmkwNDREB3VuaTA0NEUHdW5pMDQ0Rgd1bmkwNDUyB3VuaTA0NTQHdW5pMDQ1OQd1bmkwNDVBB3VuaTA0NUIHdW5pMDQ1Rgd1bmkwNDYwB3VuaTA0NjEHdW5pMDQ2Mwd1bmkwNDY0B3VuaTA0NjUHdW5pMDQ2Ngd1bmkwNDY3B3VuaTA0NjgHdW5pMDQ2OQd1bmkwNDZBB3VuaTA0NkIHdW5pMDQ2Qwd1bmkwNDZEB3VuaTA0NkUHdW5pMDQ2Rgd1bmkwNDcyB3VuaTA0NzMHdW5pMDQ3NAd1bmkwNDc1B3VuaTA0NzgHdW5pMDQ3OQd1bmkwNDdBB3VuaTA0N0IHdW5pMDQ3Qwd1bmkwNDdEB3VuaTA0N0UHdW5pMDQ3Rgd1bmkwNDgwB3VuaTA0ODEHdW5pMDQ4Mgd1bmkwNDgzB3VuaTA0ODQHdW5pMDQ4NQd1bmkwNDg2B3VuaTA0ODgHdW5pMDQ4OQd1bmkwNDhFB3VuaTA0OEYHdW5pMDQ5MAd1bmkwNDkxB3VuaTA0OTQHdW5pMDQ5NQd1bmkwNDlDB3VuaTA0OUQHdW5pMDRBMAd1bmkwNEExB3VuaTA0QTQHdW5pMDRBNQd1bmkwNEE2B3VuaTA0QTcHdW5pMDRBOAd1bmkwNEE5B3VuaTA0QjQHdW5pMDRCNQd1bmkwNEI4B3VuaTA0QjkHdW5pMDRCQQd1bmkwNEJDB3VuaTA0QkQHdW5pMDRDMwd1bmkwNEM0B3VuaTA0QzcHdW5pMDRDOAd1bmkwNEQ4B3VuaTA0RTAHdW5pMDRFMQd1bmkwNEZBB3VuaTA0RkIHdW5pMDUwMAd1bmkwNTAyB3VuaTA1MDMHdW5pMDUwNAd1bmkwNTA1B3VuaTA1MDYHdW5pMDUwNwd1bmkwNTA4B3VuaTA1MDkHdW5pMDUwQQd1bmkwNTBCB3VuaTA1MEMHdW5pMDUwRAd1bmkwNTBFB3VuaTA1MEYHdW5pMDUxMAd1bmkyMDAwB3VuaTIwMDEHdW5pMjAwMgd1bmkyMDAzB3VuaTIwMDQHdW5pMjAwNQd1bmkyMDA2B3VuaTIwMDcHdW5pMjAwOAd1bmkyMDA5B3VuaTIwMEEHdW5pMjAwQg11bmRlcnNjb3JlZGJsDXF1b3RlcmV2ZXJzZWQHdW5pMjAyNQd1bmkyMDc0CW5zdXBlcmlvcgRFdXJvB3VuaTIxMDUHdW5pMjExMwd1bmkyMTE2CWVzdGltYXRlZAlvbmVlaWdodGgMdGhyZWVlaWdodGhzC2ZpdmVlaWdodGhzDHNldmVuZWlnaHRocwd1bmlGRUZGB3VuaUZGRkMHdW5pRkZGRBNjaXJjdW1mbGV4dGlsZGVjb21iEmNpcmN1bWZsZXhob29rY29tYhNjaXJjdW1mbGV4Z3JhdmVjb21iE2NpcmN1bWZsZXhhY3V0ZWNvbWIOYnJldmVncmF2ZWNvbWIRY29tbWFhY2NlbnRyb3RhdGUGQS5zbWNwBkIuc21jcAZDLnNtY3AGRC5zbWNwBkUuc21jcAZGLnNtY3AGRy5zbWNwBkguc21jcAZJLnNtY3AGSi5zbWNwBksuc21jcAZMLnNtY3AGTS5zbWNwBk4uc21jcAZPLnNtY3AGUS5zbWNwBlIuc21jcAZTLnNtY3AGVC5zbWNwBlUuc21jcAZWLnNtY3AGVy5zbWNwBlguc21jcAZZLnNtY3AGWi5zbWNwDWJyZXZlaG9va2NvbWIOYnJldmVhY3V0ZWNvbWIIY3Jvc3NiYXIJcmluZ2FjdXRlCWRhc2lhb3hpYQ5icmV2ZXRpbGRlY29tYgtjeXJpbGxpY3RpYwxjeXJpbGxpY2hvb2sGUC5zbWNwBUsuYWx0D0dlcm1hbmRibHMuc21jcAd1bmkwMEFEB3VuaTAxMEEHdW5pMDEwQgd1bmkwMTIwB3VuaTAxMjELbmFwb3N0cm9waGUHdW5pMDIxOAd1bmkwMjE5B3VuaTAyMUEHdW5pMDIxQgd1bmkwMTYyDHVuaTAxNjIuc21jcAd1bmkwMTYzC0Rjcm9hdC5zbWNwCEV0aC5zbWNwCVRiYXIuc21jcAtBZ3JhdmUuc21jcAtBYWN1dGUuc21jcBBBY2lyY3VtZmxleC5zbWNwC0F0aWxkZS5zbWNwDkFkaWVyZXNpcy5zbWNwCkFyaW5nLnNtY3APQXJpbmdhY3V0ZS5zbWNwDUNjZWRpbGxhLnNtY3ALRWdyYXZlLnNtY3ALRWFjdXRlLnNtY3AQRWNpcmN1bWZsZXguc21jcA5FZGllcmVzaXMuc21jcAtJZ3JhdmUuc21jcAtJYWN1dGUuc21jcBBJY2lyY3VtZmxleC5zbWNwDklkaWVyZXNpcy5zbWNwC050aWxkZS5zbWNwC09ncmF2ZS5zbWNwC09hY3V0ZS5zbWNwEE9jaXJjdW1mbGV4LnNtY3ALT3RpbGRlLnNtY3AOT2RpZXJlc2lzLnNtY3ALVWdyYXZlLnNtY3ALVWFjdXRlLnNtY3AQVWNpcmN1bWZsZXguc21jcA5VZGllcmVzaXMuc21jcAtZYWN1dGUuc21jcAxBbWFjcm9uLnNtY3ALQWJyZXZlLnNtY3AMQW9nb25lay5zbWNwC0NhY3V0ZS5zbWNwEENjaXJjdW1mbGV4LnNtY3ALQ2Nhcm9uLnNtY3ALRGNhcm9uLnNtY3AMRW1hY3Jvbi5zbWNwC0VicmV2ZS5zbWNwD0Vkb3RhY2NlbnQuc21jcAxFb2dvbmVrLnNtY3ALRWNhcm9uLnNtY3AQR2NpcmN1bWZsZXguc21jcAtHYnJldmUuc21jcBFHY29tbWFhY2NlbnQuc21jcBBIY2lyY3VtZmxleC5zbWNwC0l0aWxkZS5zbWNwDEltYWNyb24uc21jcAtJYnJldmUuc21jcAxJb2dvbmVrLnNtY3APSWRvdGFjY2VudC5zbWNwEEpjaXJjdW1mbGV4LnNtY3ARS2NvbW1hYWNjZW50LnNtY3ALTGFjdXRlLnNtY3ARTGNvbW1hYWNjZW50LnNtY3ALTGNhcm9uLnNtY3AJTGRvdC5zbWNwC05hY3V0ZS5zbWNwEU5jb21tYWFjY2VudC5zbWNwC05jYXJvbi5zbWNwDE9tYWNyb24uc21jcAtPYnJldmUuc21jcBJPaHVuZ2FydW1sYXV0LnNtY3ALUmFjdXRlLnNtY3ARUmNvbW1hYWNjZW50LnNtY3ALUmNhcm9uLnNtY3ALU2FjdXRlLnNtY3AQU2NpcmN1bWZsZXguc21jcA1TY2VkaWxsYS5zbWNwC1NjYXJvbi5zbWNwC1RjYXJvbi5zbWNwC1V0aWxkZS5zbWNwDFVtYWNyb24uc21jcAtVYnJldmUuc21jcApVcmluZy5zbWNwElVodW5nYXJ1bWxhdXQuc21jcAxVb2dvbmVrLnNtY3AQV2NpcmN1bWZsZXguc21jcBBZY2lyY3VtZmxleC5zbWNwDllkaWVyZXNpcy5zbWNwC1phY3V0ZS5zbWNwD1pkb3RhY2NlbnQuc21jcAtaY2Fyb24uc21jcApBbHBoYXRvbm9zDEVwc2lsb250b25vcwhFdGF0b25vcwlJb3RhdG9ub3MMT21pY3JvbnRvbm9zDFVwc2lsb250b25vcwpPbWVnYXRvbm9zEWlvdGFkaWVyZXNpc3Rvbm9zBUFscGhhBEJldGEHRXBzaWxvbgRaZXRhA0V0YQRJb3RhBUthcHBhAk11Ak51B09taWNyb24DUmhvA1RhdQdVcHNpbG9uA0NoaQxJb3RhZGllcmVzaXMPVXBzaWxvbmRpZXJlc2lzCmFscGhhdG9ub3MMZXBzaWxvbnRvbm9zCGV0YXRvbm9zCWlvdGF0b25vcxR1cHNpbG9uZGllcmVzaXN0b25vcwVrYXBwYQdvbWljcm9uB3VuaTAzQkMCbnUDY2hpDGlvdGFkaWVyZXNpcw91cHNpbG9uZGllcmVzaXMMb21pY3JvbnRvbm9zDHVwc2lsb250b25vcwpvbWVnYXRvbm9zB3VuaTA0MDEHdW5pMDQwMwd1bmkwNDA1B3VuaTA0MDYHdW5pMDQwNwd1bmkwNDA4B3VuaTA0MUEHdW5pMDQwQwd1bmkwNDBFB3VuaTA0MTAHdW5pMDQxMgd1bmkwNDEzB3VuaTA0MTUHdW5pMDQxOQd1bmkwNDFDB3VuaTA0MUQHdW5pMDQxRQd1bmkwNDFGB3VuaTA0MjAHdW5pMDQyMQd1bmkwNDIyB3VuaTA0MjQHdW5pMDQyNQd1bmkwNDMwB3VuaTA0MzUHdW5pMDQzOQd1bmkwNDNFB3VuaTA0NDAHdW5pMDQ0MQd1bmkwNDQzB3VuaTA0NDUHdW5pMDQ1MQd1bmkwNDUzB3VuaTA0NTUHdW5pMDQ1Ngd1bmkwNDU3B3VuaTA0NTgHdW5pMDQ1Qwd1bmkwNDVFCWV4Y2xhbWRibAd1bmkwMUYwB3VuaTAyQkMHdW5pMUUzRQd1bmkxRTNGB3VuaTFFMDAHdW5pMUUwMQd1bmkxRjREB3VuaTA0MDAHdW5pMDQwRAd1bmkwNDUwB3VuaTA0NUQHdW5pMDQ3MAd1bmkwNDcxB3VuaTA0NzYHdW5pMDQ3Nwd1bmkwNDk4B3VuaTA0OTkHdW5pMDRBQQd1bmkwNEFCB3VuaTA0QUUHdW5pMDRBRgd1bmkwNEMwB3VuaTA0QzEHdW5pMDRDMgd1bmkwNENGB3VuaTA0RDAHdW5pMDREMQd1bmkwNEQyB3VuaTA0RDMHdW5pMDRENAd1bmkwNEQ1B3VuaTA0RDYHdW5pMDRENwd1bmkwNERBB3VuaTA0RDkHdW5pMDREQgd1bmkwNERDB3VuaTA0REQHdW5pMDRERQd1bmkwNERGB3VuaTA0RTIHdW5pMDRFMwd1bmkwNEU0B3VuaTA0RTUHdW5pMDRFNgd1bmkwNEU3B3VuaTA0RTgHdW5pMDRFOQd1bmkwNEVBB3VuaTA0RUIHdW5pMDRFQwd1bmkwNEVEB3VuaTA0RUUHdW5pMDRFRgd1bmkwNEYwB3VuaTA0RjEHdW5pMDRGMgd1bmkwNEYzB3VuaTA0RjQHdW5pMDRGNQd1bmkwNEY4B3VuaTA0RjkHdW5pMDRGQwd1bmkwNEZEB3VuaTA1MDEHdW5pMDUxMgd1bmkwNTEzB3VuaTFFQTAHdW5pMUVBMQd1bmkxRUEyB3VuaTFFQTMHdW5pMUVBNAd1bmkxRUE1B3VuaTFFQTYHdW5pMUVBNwd1bmkxRUE4B3VuaTFFQTkHdW5pMUVBQQd1bmkxRUFCB3VuaTFFQUMHdW5pMUVBRAd1bmkxRUFFB3VuaTFFQUYHdW5pMUVCMAd1bmkxRUIxB3VuaTFFQjIHdW5pMUVCMwd1bmkxRUI0B3VuaTFFQjUHdW5pMUVCNgd1bmkxRUI3B3VuaTFFQjgHdW5pMUVCOQd1bmkxRUJBB3VuaTFFQkIHdW5pMUVCQwd1bmkxRUJEB3VuaTFFQkUHdW5pMUVCRgd1bmkxRUMwB3VuaTFFQzEHdW5pMUVDMgd1bmkxRUMzB3VuaTFFQzQHdW5pMUVDNQd1bmkxRUM2B3VuaTFFQzcHdW5pMUVDOAd1bmkxRUM5B3VuaTFFQ0EHdW5pMUVDQgd1bmkxRUNDB3VuaTFFQ0QHdW5pMUVDRQd1bmkxRUNGB3VuaTFFRDAHdW5pMUVEMQd1bmkxRUQyB3VuaTFFRDMHdW5pMUVENAd1bmkxRUQ1B3VuaTFFRDYHdW5pMUVENwd1bmkxRUQ4B3VuaTFFRDkHdW5pMUVEQQd1bmkxRURCB3VuaTFFREMHdW5pMUVERAd1bmkxRURFB3VuaTFFREYHdW5pMUVFMAd1bmkxRUUxB3VuaTFFRTIHdW5pMUVFMwd1bmkxRUU0B3VuaTFFRTUHdW5pMUVFNgd1bmkxRUU3B3VuaTFFRTgHdW5pMUVFOQd1bmkxRUVBB3VuaTFFRUIHdW5pMUVFQwd1bmkxRUVEB3VuaTFFRUUHdW5pMUVFRgd1bmkxRUYwB3VuaTFFRjEHdW5pMUVGNAd1bmkxRUY1B3VuaTFFRjYHdW5pMUVGNwd1bmkxRUY4B3VuaTFFRjkHdW5pMjBBQgd1bmkwNDlBB3VuaTA0OUIHdW5pMDRBMgd1bmkwNEEzB3VuaTA0QUMHdW5pMDRBRAd1bmkwNEIyB3VuaTA0QjMHdW5pMDRCNgd1bmkwNEI3B3VuaTA0Q0IHdW5pMDRDQwd1bmkwNEY2B3VuaTA0RjcHdW5pMDQ5Ngd1bmkwNDk3B3VuaTA0QkUHdW5pMDRCRgd1bmkwNEJCB3VuaTA0OEQHdW5pMDQ4Qwd1bmkwNDYyB3VuaTA0OTIHdW5pMDQ5Mwd1bmkwNDlFB3VuaTA0OUYHdW5pMDQ4QQd1bmkwNDhCB3VuaTA0QzkHdW5pMDRDQQd1bmkwNENEB3VuaTA0Q0UHdW5pMDRDNQd1bmkwNEM2B3VuaTA0QjAHdW5pMDRCMQd1bmkwNEZFB3VuaTA0RkYHdW5pMDUxMQd1bmkyMDE1AAEAAf//AA8AAQAAAAoAMAA+AARERkxUABpjeXJsABpncmVrABpsYXRuABoABAAAAAD//wABAAAAAXNtY3AACAAAAAEAAAABAAQAAQAAAAEACAACAb4A3AJPAlACUQJSAlMCVAJVAlYCVwJYAlkCWgJbAlwCXQJwAl4CXwJgAmECYgJjAmQCZQJmAmcCTwJQAlECUgJTAlQCVQJWAlcCWAJZAloCWwJcAl0CcAJeAl8CYAJhAmICYwJkAmUCZgJnAoICcgKFAqAChgKIAoQCnwKhAokCigKHAqICpAKLAqMCpQKBAo0CpwKqAo4CjwKoAowCpgKpAoICrAKrAq0CrgKRArECkgKTArMCkAKwArICrwK0ArUCtgK4ArcCuQK6ArwCuwKUApYCvgKXApkClQK/Ar0CmALAAsICwQLDAsYCxQLEAoMCxwKbAsoCnAKdApoCzALJAs0CywLIAs4CngLPAtAC0QLTAtIChQKgAoYCiAKEAp8CoQKJAooChwKiAqQCiwKjAqUCgQKNAqcCqgKOAo8CqAKMAqYCqQKsAqsCrQKuApECsQKSApMCkAKwArICrwK0ArUCtgK4ArcCuQK6ArwCuwKUApYCvgKXApkClQK/Ar0CmALAAsICwQLDAsYCxQLEAoMCxwKbAsoCnAKdApoCzALJAs0CywLIAs4CngLPAtAC0QLTAtICfwJ/AAIAGgACADUAAABMAEwANABQAFAANQCeAKcANgCpALYAQAC4ALwATgC+AM0AUwDPANcAYwDZANoAbADdAOsAbgDtAPEAfQDzAPMAggD2APgAgwD6AQYAhgEIARUAkwEXARoAoQEcASoApQEsATQAtAE2ATcAvQE6AUgAvwFKAU4AzgFQAVAA0wFTAVUA1AFXAVkA1wJ+An4A2gKAAoAA2wABAAEACAACAAAAFAACAAAAJAACd2dodAEAAABpdGFsAQsAAQAEABQAAwAAAAIBDgGQAAACvAAAAAMAAQACAREAAAAAAAEAAA==) -} - -@font-face { - font-family: Roboto Mono; - font-weight: 500; - src: url(data:font/ttf;base64,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AIT+pARCBE4GJgAcAAAABwFlBI4ACP//ADIAAASzB8cGJgACAAAABwF2BNEBSf//AIT/7ARCBoUGJgAcAAAABwF2BLoAB///ADIAAAUHB+gGJgACAAAABwJM//MBXP//AIT/7ATvBqYGJgAcAAAABgJM3Br////kAAAEswfXBiYAAgAAAAcCS//jAUT////M/+wEQgaVBiYAHAAAAAYCS8wD//8AMgAABLUH+AYmAAIAAAAHAkr/+AE6//8AhP/sBJ4GtwYmABwAAAAGAkri+f//ADIAAASzCC0GJgACAAAABwJJ/+0BOf//AIT/7ARCBuwGJgAcAAAABgJJ1fj//wAy/p8EswdJBiYAAgAAACcBXACGAVwABwFlBM8AA///AIT+pARCBgcGJgAcAAAAJgFcbxoABwFlBI4ACP//ADIAAASzB8sGJgACAAAABwJp//oBT///AIT/7ARCBokGJgAcAAAABgJp4g3//wAyAAAEswgSBiYAAgAAAAcCTf//AZb//wCE/+wEQgbQBiYAHAAAAAYCTehU//8AMgAABLMIPQYmAAIAAAAHAmj/6AFC//8AhP/sBEIG/AYmABwAAAAGAmjRAf//ADIAAASzCCIGJgACAAAABwJt/8wBSP//AIT/7ARCBuEGJgAcAAAABgJttQb//wAy/p8EswdFBiYAAgAAACcBXwAGAZwABwFlBM8AA///AIT+pARCBgMGJgAcAAAAJgFf8FoABwFlBI4ACP//AKL+pgRSBbAGJgAGAAAABwFlBNgACv//AHr+nARZBE4GJgAgAAAABwFlBNoAAP//AKIAAARSB8EGJgAGAAAABwF2BNIBQ///AHr/7ARZBoYGJgAgAAAABwF2BLsACP//AKIAAARSB1cGJgAGAAAABwFdAJEBWv//AHr/7ARZBhsGJgAgAAAABgFdeR7//wCiAAAFCAfiBiYABgAAAAcCTP/0AVf//wB6/+wE8AanBiYAIAAAAAYCTNwb////5QAABFIH0QYmAAYAAAAHAkv/5AE/////zf/sBFkGlgYmACAAAAAGAkvMA///AKIAAAS2B/MGJgAGAAAABwJK//oBNP//AHr/7ASfBrgGJgAgAAAABgJK4vr//wCiAAAEUggoBiYABgAAAAcCSf/uATT//wB6/+wEWQbtBiYAIAAAAAYCSdb5//8Aov6mBFIHQwYm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fzR/PH9Ef1B/XH9of3N/fn+Jf5F/mX+hf61/uH/Af8x/13/jf+5/9n/+gAqAFYAhgCmANIBAgEuAV4BigG6AeYCFgJCAnICngK+At4DDgM6A2oDlgPGA/IEIgROBH4ErgTeBQoFOgVmBZYFxgXmBhYGRgZ2BqYG1gcGBzYHYgeSB74H7ggaCEoIdgi2CPIJIglOCX4JqgnaCgYKNgpiCqIK3gsOCz4LbgueC84L+gwqDFYMhgyyDOINDg0+DWoNqg3mDhYORg52DqYO1g8GDzYPZg+WD8IP8hAeEE4QehCqENYRFhFSEYIRrhHeEg4SPhJuEp4SyhL6EyoTWhOKE7oT6hQaFEYUdhSmFNYVBhU2FWIVkhXCFfIWIhZSFoIWshbiFx4XThd+F64X3hgOGD4YbhieGM4Y/hkuGV4Zjhm+Ge4aHhpOGnoamhuOHHodZh3OHjIeyh9eH54f2iAKIDogaiCaIMog+iGOIhYiuiNeI34jsAAEAAAADAAAlroXOXw889QALCAAAAAAAxPARLgAAAADa2D+r/AX91QZHCGIAAAAJAAIAAAAAAAAEzQAAAAAAMgCTAFsAigCiAKcAXACDALkAagCTAKoAiACDAFsApwBZAJgAZQAwAIMAMAAuADYALQBjAIQAnwCAAHsAegCJAHwAmwDSANoAnQDJAFMAmwBvAJ0AfAExAJAAhQCjAFMAJABiADsAiACPALwATABfAEIAkgB4AFcAigB3AYcBMgEyARYBDQAdADoAIwApAC0ASgApADUAlQCdAKoApQClAI4AkAByABoAmQAHAGwAfQBbAdIB6QCtAMsBZQHFAeIByQCqAfIBlwCXAP8AQgBCAdkBOAHrAdAByAFHASwBOQHZATgBXgE+AZsBkgE7AUgBigGGAGsAnQCXAKcAbwCkAJ8AjgCiAKgAsgC1ALsA6QDsASAAJwBCAhgB8gBvAH0AWQBYAG4BZwCdADEAWAAwAFYA1gDdACMAMgAyADIAMgAyADIAMgAyADIAMgApAFsAWwBbAFsAiv/PAKIAogCiAKIAogCiAKIAogCfAKL/zwBcAFwAXAAXAIMAuQC5ALkAuQC5ALkAuQC5ALkAagCTAKoAqgCqAKoANgCDAIMAgwCDAFsAWwBbAFsAWwBgAFsAWwA6ADoAWwCYAJgAmABlAGUAZQBlADAAMACDAIMAgwCDAIMAiACDAIMAgwCDAIMALgAuAC4ALgAtAC0ALQAtAGMAYwBjAIQAhACEAIQAhACEAIQAhACEAIQALQCAAIAAgACAAEEAbAB6AHoAegB6AHoAegB6AHoApAB6AHwAfAB8AAL/wADJAMkAyQDJAMkAyQDSAMkAzQCdAMkAiwDJAIMA0QCbAJsAmwCbAG8AbwBvAG8AbwBpAG8AbwBvAG8AbwExAOYBDQCQAJAAkACQAIUAcQCjAKMAowCjAKMAkACjAKMAowCjAKMAJAAkACQAJAA7ADsAOwA7AIgAiACIAZ0BigCcAIQBCgEuAeMBEgGWAOEBEP0YAcIBhAEfAAAAxQCzAOkAyQB/AE0BrgDNAbT8rf1t/Hn9O/v9AjkBCgIuAJ4AKABhACQAgwCKAG8AQwBSAFsAdAClADUAaACHAGAAkAC0ALUAKgCwAF8AkgBkAFwAbgCLAFsAUQA8AJYAPQATACQAbQAjAGwAMwCDAJAANwAIAFMAhAAqABMAhQCjAGMAYwAzAGcAkwBDAGMABQB5AJUAoAAqABsAewCLAJIALAB7AIsAiwBiAFMAjgCDAGYAXwA4AHYAlQB3AE8ATv/ZAHoAHQBrAAgAiwBWAFAAIABVAG4AGABRAF8AXwA+AFIAQQBFAKkAxgBXAF8AEgBBAEUANQBbAHAAPABWAFwAUACIALcAcP6x/qn/j/+u/qP+xQCnAJ0ApQCjAJ8ApACXAJEAHAAnAFQAYABLAGEAXwBNABkAKQCVAIEApP/3ABwAswCkAJ4AngBTAIYAfAAzAFsAVQBWAF8APABNAK0AxwARACsAWABZAHUAkABHAEUAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChAcgBHQEOATgAfAA9ALoAeACWAFoAJgAfAEUAdQChACsALQA3AO8AhwAAAFkADwEaAQgAAQEOATMB5gAjALUAXwCoALEAwgBrAJMA0ACcAKUAtQCHAK4AcwBgAJIAhgBYAKcAPgAnAE0AQgCmAUUBNQEwAcgB9AFmAf8BTwCzAJ8ArQAAAP8AWwCAAFwAfP+JAGUAkAAwAIUAMABYAIX/xP/EAFgAIwAjACMAIwAjACMAIwBfALEAsQCxALEA0ADQANAA0ACuAHMAcwBzAHMAcwCnAKcApwCnAEIAIwAjACMAXwBfAF8AkQCxALEAsQCxALEAawBr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AS8BNAEwATIBOgEzAIABOAFIAUQBRgFHAVMATgFVAKMBAgCfAP4ApAEDAKkBCACsAQsCdQJ2AKoBCQCtAQwArgENALYBFQCwAQ8AtAETALgBFwCxARAAuwEZALoBGAJ3AngAvAEaAL4BHAC9ARsAxwEkAMUBIgDAAR4AxgEjAMMBbQFuAW8AyAElAMkBJgBPAMoBJwDMASkAywEoAM0BKgDOASsAzwEsANEBLgDQAS0CeQC3ARYA2gE3ANQBMQDZATYASgBLAN4BOwDgAT0A3wE8AOEBPgDkAUEA4wFAAOIBPwJ+AoAA5gFDAOUBQgDxAU4A7gFLAOgBRQDwAU0A7QFKAO8BTADzAVAA9wFUAPgA+gFXAPwBWQD7AVgBcADYATUA7AFJAKYBBQCoAQcA3AE5AVwBZAFfAWABYgFnAV0BYwF4AXkC1AF6AtUC1gLXAXsBfALeAt8C4AF9AuEC4gF+AuMC5AF/AuUBgALmAYEC5wLoAYIC6QGDAYQC6gLrAuwC7QLuAu8C8ALxAY4C8wL0AY8C8gGQAZEBkgGTAZQBlQGWAvUBlwGYAyoC+wGcAvwBnQL9Av4C/wMAAZ4BnwGgAwIDKwMDAaEDBAGiAwUDBgGjAwcBpAGlAaYDCAMBAacDCQMKAwsDDAMNAw4DDwGoAxADEQMSAbMBtAG1AbYDEwG3AbgBuQMUAboBuwG8Ab0DFQG+AxYDFwG/AxgBwAMZAywDGgHLAxsBzAMcAx0DHgMfAc0BzgHPAyADLQMhAdAB0QHSA9QDLgMvAeAB4QHiAeMDMAMxAfMB9APZA9oD0wPSAfUB9gH3AfgD1QPWAfkB+gPNA84DMgMzA78DwAH7AfwD1wPYAf0B/gPBA8IB/wIAAgECAgIDAgQDNAM1A8MDxAM2AzcD4QPiA8UDxgIFAgYDxwPIAgcCCAIJA9ECCgILA88D0AM4AzkDOgIMAg0D3wPgAg4CDwPbA9wDyQPKA90D3gIQA0UDRANGA0cDSANJA0oCEQISA8sDzANfA2ACEwIUA2EDYgPjA+QCFQNjA+UDZANlAPUBUgDyAU8A9AFRAPkBVgBoAGkD5gIxAGwAbQBuAjIAbwBwAHEAkACRAGUCMwBjA74CNgJBAH24Af+FsASNAAAAABMA6gADAAEECQAAALQAAAADAAEECQABACQAtAADAAEECQACAA4A2AADAAEECQADADgA5gADAAEECQAEACQAtAADAAEECQAFABoBHgADAAEECQAGACIBOAADAAEECQAHAEoBWgADAAEECQAJAAwBpAADAAEECQALABQBsAADAAEECQAMACYBxAADAAEECQANAFwB6gADAAEECQAOAFQCRgADAAEECQAQABYCmgADAAEECQARAAwCsAADAAEECQEAAAwCvAADAAEECQELAAwCyAADAAEECQEPAAwCsAADAAEECQERAAwC1ABDAG8AcAB5AHIAaQBnAGgAdAAgADIAMAAxADUAIABUAGgAZQAgAFIAbwBiAG8AdABvACAATQBvAG4AbwAgAFAAcgBvAGoAZQBjAHQAIABBAHUAdABoAG8AcgBzACAAKABoAHQAdABwAHMAOgAvAC8AZwBpAHQAaAB1AGIALgBjAG8AbQAvAGcAbwBvAGcAbABlAGYAbwBuAHQAcwAvAHIAbwBiAG8AdABvAG0AbwBuAG8AKQBSAG8AYgBvAHQAbwAgAE0AbwBuAG8AIABNAGUAZABpAHUAbQBSAGUAZwB1AGwAYQByADMALgAwADAAMAA7AEcATwBPAEcAOwBSAG8AYgBvAHQAbwBNAG8AbgBvAC0ATQBlAGQAaQB1AG0AVgBlAHIAcwBpAG8AbgAgADMALgAwADAAMABSAG8AYgBvAHQAbwBNAG8AbgBvAC0ATQBlAGQAaQB1AG0AUgBvAGIAbwB0AG8AIABNAG8AbgBvACAAaQBzACAAYQAgAHQAcgBhAGQAZQBtAGEAcgBrACAAbwBmACAARwBvAG8AZwBsAGUALgBHAG8AbwBnAGwAZQBHAG8AbwBnAGwAZQAuAGMAbwBtAEMAaAByAGkAcwB0AGkAYQBuACAAUgBvAGIAZQByAHQAcwBvAG4ATABpAGMAZQBuAHMAZQBkACAAdQBuAGQAZQByACAAdABoAGUAIABBAHAAYQBjAGgAZQAgAEwAaQBjAGUAbgBzAGUALAAgAFYAZQByAHMAaQBvAG4AIAAyAC4AMABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBwAGEAYwBoAGUALgBvAHIAZwAvAGwAaQBjAGUAbgBzAGUAcwAvAEwASQBDAEUATgBTAEUALQAyAC4AMABSAG8AYgBvAHQAbwAgAE0AbwBuAG8ATQBlAGQAaQB1AG0AVwBlAGkAZwBoAHQASQB0AGEAbABpAGMATgBvAHIAbQBhAGwAAAACAAAAAAAA/2oAZAAAAAEAAAAAAAAAAAAAAAAAAAAAA+cAAAADACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQBEAEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AEwAUABUAFgAXABgAGQAaABsAHADxAPIA8wCdAJ4A9AD1APYAkACgALAAsQDqAO0A7gECAIkBAwAHAIQAhQCWAKYA9wEEAQUAvQAEAKMAIgCiAA8AEQAdAB4AqwDDAIcAQgAQALIAswAKAAUAtgC3AMQAtAC1AMUBBgEHAAsADAA+AEAAXgBgAL4AvwAOAO8AkwDwALgAIACPAKcAHwAhAJQAlQCkABIAPwC8AAgAxgBfAOgAggDCAIsAigCMAIMADQAGAAkAIwCGAIgAQQBhAMkBCADHAGIArQEJAQoAYwELAK4BDAD9AP8AZAENAQ4BDwBlARABEQDIAMoBEgDLARMBFAEVAOkA+AEWARcBGAEZAMwBGgDNAM4A+gDPARsBHAEdAR4BHwEgASEBIgEjAOIBJAElASYAZgDQAScA0QBnANMBKAEpASoAkQErAK8BLAEtAS4BLwDkAPsBMAExATIA1AEzANUAaADWATQBNQE2ATcBOAE5AToBOwE8AT0A6wE+ALsBPwFAAOYBQQBpAUIAawBsAGoBQwFEAG4BRQBtAUYA/gEAAG8BRwFIAQEAcAFJAUoAcgBzAUsAcQFMAU0BTgD5AU8BUAFRAVIAdAFTAHYAdwB1AVQBVQFWAVcBWAFZAVoBWwFcAOMBXQFeAV8AeAB5AWAAewB8AHoBYQFiAWMAoQFkAH0BZQFmAWcBaADlAPwBaQFqAWsAfgFsAIAAgQB/AW0BbgFvAXABcQFyAXMBdAF1AXYA7AF3ALoBeAF5AOcBegBDAI0A2ADZANoA2wDcAI4A3QDfAOEBewDeAOABfAACAKkAlwCqANcBfQF+AX8BgAGBAYIBgwGEAYUBhgGHAYgBiQGKAKgBiwGMAY0BjgGPAZABkQCfAZIBkwGUAZUBlgGXAZgBmQGaAZsBnACbAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0BzgHPAdAB0QHSAdMB1AHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gHzAfQB9QH2AfcB+AH5AfoB+wH8Af0B/gH/AgACAQICAgMCBAIFAgYCBwIIAgkCCgILAgwCDQIOAg8CEAIRAhICEwIUAhUCFgIXAhgCGQIaAhsCHAIdAh4CHwIgAiECIgIjAiQCJQImAicCKAIpAioCKwIsAi0CLgIvAjACMQIyAjMCNAI1AjYCNwI4AjkCOgI7AjwCPQI+Aj8CQAJBAkICQwJEAkUCRgJHAkgCSQJKAJgAmgCZAKUAkgCcALkCSwJMAk0CTgJPAlACUQJSAlMCVAJVAlYCVwJYAlkCWgJbAlwCXQJeAl8CYAJhAmICYwJkAmUCZgJnAmgCaQJqAmsCbAJtAm4CbwJwAnECcgJzAnQCdQJ2AncArAJ4AnkCegJ7AnwCfQJ+An8CgAKBAoICgwKEAoUChgKHAogCiQKKAosCjAKNAo4CjwKQApECkgKTApQClQKWApcCmAKZApoCmwKcAp0CngKfAqACoQKiAqMCpAKlAqYCpwKoAqkCqgKrAqwCrQKuAq8CsAKxArICswK0ArUCtgK3ArgCuQK6ArsCvAK9Ar4CvwLAAsECwgLDAsQCxQLGAscCyALJAsoCywLMAs0CzgLPAtAC0QLSAtMC1ALVAtYC1wLYAtkC2gLbAtwC3QLeAt8C4ALhAuIC4wLkAuUC5gLnAugC6QLqAusC7ALtAu4C7wLwAvEC8gLzAvQC9QL2AvcC+AL5AvoC+wL8Av0C/gL/AwADAQMCAwMDBAMFAwYDBwMIAwkDCgMLAwwDDQMOAw8DEAMRAxIDEwMUAxUDFgMXAxgDGQMaAxsDHAMdAx4DHwMgAyEDIgMjAyQDJQMmAycDKAMpAyoDKwMsAy0DLgMvAzADMQMyAzMDNAM1AzYDNwM4AzkDOgM7AzwDPQM+Az8DQANBA0IDQwNEA0UDRgNHA0gDSQNKA0sDTANNA04DTwNQA1EDUgNTA1QDVQNWA1cDWANZA1oDWwNcA10DXgNfA2ADYQNiA2MDZANlA2YDZwNoA2kDagNrA2wDbQNuA28DcANxA3IDcwN0A3UDdgN3A3gDeQN6A3sDfAN9A34DfwOAA4EDggODA4QDhQOGA4cDiAOJA4oDiwOMA40DjgOPA5ADkQOSA5MDlAOVA5YDlwOYA5kDmgObA5wDnQOeA58DoAOhA6IDowOkA6UDpgOnA6gDqQOqA6sDrAOtA64DrwOwA7EDsgOzA7QDtQO2A7cDuAO5A7oDuwO8A70DvgO/A8ADwQPCA8MDxAPFA8YDxwPIA8kDygPLA8wDzQPOA88D0APRA9ID0wPUA9UD1gPXA9gD2QPaA9sD3APdA94D3wPgA+ED4gPjA+QD5QPmA+cD6APpA+oMa2dyZWVubGFuZGljBXNjaHdhBGxpcmEGcGVzZXRhBm1pbnV0ZQZzZWNvbmQGQWJyZXZlB0FtYWNyb24HQW9nb25lawpBcmluZ2FjdXRlB0FFYWN1dGULQ2NpcmN1bWZsZXgGRGNhcm9uBkRjcm9hdAZFYnJldmUGRWNhcm9uCkVkb3RhY2NlbnQHRW1hY3JvbgNFbmcHRW9nb25lawtHY2lyY3VtZmxleAxHY29tbWFhY2NlbnQESGJhcgtIY2lyY3VtZmxleAZJYnJldmUHSW1hY3JvbgdJb2dvbmVrBkl0aWxkZQtKY2lyY3VtZmxleAxLY29tbWFhY2NlbnQGTGFjdXRlBkxjYXJvbgxMY29tbWFhY2NlbnQETGRvdAZOYWN1dGUGTmNhcm9uDE5jb21tYWFjY2VudAZPYnJldmUFT2hvcm4NT2h1bmdhcnVtbGF1dAdPbWFjcm9uC09zbGFzaGFjdXRlBlJhY3V0ZQZSY2Fyb24MUmNvbW1hYWNjZW50BlNhY3V0ZQtTY2lyY3VtZmxleARUYmFyBlRjYXJvbgZVYnJldmUFVWhvcm4NVWh1bmdhcnVtbGF1dAdVbWFjcm9uB1VvZ29uZWsFVXJpbmcGVXRpbGRlBldhY3V0ZQtXY2lyY3VtZmxleAlXZGllcmVzaXMGV2dyYXZlC1ljaXJjdW1mbGV4BllncmF2ZQZaYWN1dGUKWmRvdGFjY2VudAZhYnJldmUHYW1hY3Jvbgdhb2dvbmVrCmFyaW5nYWN1dGUHYWVhY3V0ZQtjY2lyY3VtZmxleAZkY2Fyb24GZWJyZXZlBmVjYXJvbgplZG90YWNjZW50B2VtYWNyb24DZW5nB2VvZ29uZWsLZ2NpcmN1bWZsZXgMZ2NvbW1hYWNjZW50BGhiYXILaGNpcmN1bWZsZXgGaWJyZXZlB2ltYWNyb24HaW9nb25lawZpdGlsZGULamNpcmN1bWZsZXgMa2NvbW1hYWNjZW50BmxhY3V0ZQZsY2Fyb24MbGNvbW1hYWNjZW50BGxkb3QGbmFjdXRlBm5jYXJvbgxuY29tbWFhY2NlbnQGb2JyZXZlBW9ob3JuDW9odW5nYXJ1bWxhdXQHb21hY3Jvbgtvc2xhc2hhY3V0ZQZyYWN1dGUGcmNhcm9uDHJjb21tYWFjY2VudAZzYWN1dGULc2NpcmN1bWZsZXgEdGJhcgZ0Y2Fyb24GdWJyZXZlBXVob3JuDXVodW5nYXJ1bWxhdXQHdW1hY3Jvbgd1b2dvbmVrBXVyaW5nBnV0aWxkZQZ3YWN1dGULd2NpcmN1bWZsZXgJd2RpZXJlc2lzBndncmF2ZQt5Y2lyY3VtZmxleAZ5Z3JhdmUGemFjdXRlCnpkb3RhY2NlbnQIZG90YmVsb3cLY29tbWFhY2NlbnQCSUoCaWoFbG9uZ3MHdW5pMDIzNwd1bmkwMkYzCWdyYXZlY29tYglhY3V0ZWNvbWIJdGlsZGVjb21iBGhvb2sHdW5pMDMwRgV0b25vcw1kaWVyZXNpc3Rvbm9zCWFub3RlbGVpYQVHYW1tYQVUaGV0YQZMYW1iZGECWGkCUGkFU2lnbWEDUGhpA1BzaQVhbHBoYQRiZXRhBWdhbW1hBWRlbHRhB2Vwc2lsb24EemV0YQNldGEFdGhldGEEaW90YQZsYW1iZGECeGkDcmhvBnNpZ21hMQVzaWdtYQN0YXUHdXBzaWxvbgNwaGkDcHNpBW9tZWdhB3VuaTAzRDEHdW5pMDNEMgd1bmkwM0Q2B3VuaTA0MDIHdW5pMDQwNAd1bmkwNDA5B3VuaTA0MEEHdW5pMDQwQgd1bmkwNDBGB3VuaTA0MTEHdW5pMDQxNAd1bmkwNDE2B3VuaTA0MTcHdW5pMDQxOAd1bmkwNDFCB3VuaTA0MjMHdW5pMDQyNgd1bmkwNDI3B3VuaTA0MjgHdW5pMDQyOQd1bmkwNDJBB3VuaTA0MkIHdW5pMDQyQwd1bmkwNDJEB3VuaTA0MkUHdW5pMDQyRgd1bmkwNDMxB3VuaTA0MzIHdW5pMDQzMwd1bmkwNDM0B3VuaTA0MzYHdW5pMDQzNwd1bmkwNDM4B3VuaTA0M0EHdW5pMDQzQgd1bmkwNDNDB3VuaTA0M0QHdW5pMDQzRgd1bmkwNDQyB3VuaTA0NDQHdW5pMDQ0Ngd1bmkwNDQ3B3VuaTA0NDgHdW5pMDQ0OQd1bmkwNDRBB3VuaTA0NEIHdW5pMDQ0Qwd1bmkwNDREB3VuaTA0NEUHdW5pMDQ0Rgd1bmkwNDUyB3VuaTA0NTQHdW5pMDQ1OQd1bmkwNDVBB3VuaTA0NUIHdW5pMDQ1Rgd1bmkwNDYwB3VuaTA0NjEHdW5pMDQ2Mwd1bmkwNDY0B3VuaTA0NjUHdW5pMDQ2Ngd1bmkwNDY3B3VuaTA0NjgHdW5pMDQ2OQd1bmkwNDZBB3VuaTA0NkIHdW5pMDQ2Qwd1bmkwNDZEB3VuaTA0NkUHdW5pMDQ2Rgd1bmkwNDcyB3VuaTA0NzMHdW5pMDQ3NAd1bmkwNDc1B3VuaTA0NzgHdW5pMDQ3OQd1bmkwNDdBB3VuaTA0N0IHdW5pMDQ3Qwd1bmkwNDdEB3VuaTA0N0UHdW5pMDQ3Rgd1bmkwNDgwB3VuaTA0ODEHdW5pMDQ4Mgd1bmkwNDgzB3VuaTA0ODQHdW5pMDQ4NQd1bmkwNDg2B3VuaTA0ODgHdW5pMDQ4OQd1bmkwNDhFB3VuaTA0OEYHdW5pMDQ5MAd1bmkwNDkxB3VuaTA0OTQHdW5pMDQ5NQd1bmkwNDlDB3VuaTA0OUQHdW5pMDRBMAd1bmkwNEExB3VuaTA0QTQHdW5pMDRBNQd1bmkwNEE2B3VuaTA0QTcHdW5pMDRBOAd1bmkwNEE5B3VuaTA0QjQHdW5pMDRCNQd1bmkwNEI4B3VuaTA0QjkHdW5pMDRCQQd1bmkwNEJDB3VuaTA0QkQHdW5pMDRDMwd1bmkwNEM0B3VuaTA0QzcHdW5pMDRDOAd1bmkwNEQ4B3VuaTA0RTAHdW5pMDRFMQd1bmkwNEZBB3VuaTA0RkIHdW5pMDUwMAd1bmkwNTAyB3VuaTA1MDMHdW5pMDUwNAd1bmkwNTA1B3VuaTA1MDYHdW5pMDUwNwd1bmkwNTA4B3VuaTA1MDkHdW5pMDUwQQd1bmkwNTBCB3VuaTA1MEMHdW5pMDUwRAd1bmkwNTBFB3VuaTA1MEYHdW5pMDUxMAd1bmkyMDAwB3VuaTIwMDEHdW5pMjAwMgd1bmkyMDAzB3VuaTIwMDQHdW5pMjAwNQd1bmkyMDA2B3VuaTIwMDcHdW5pMjAwOAd1bmkyMDA5B3VuaTIwMEEHdW5pMjAwQg11bmRlcnNjb3JlZGJsDXF1b3RlcmV2ZXJzZWQHdW5pMjAyNQd1bmkyMDc0CW5zdXBlcmlvcgRFdXJvB3VuaTIxMDUHdW5pMjExMwd1bmkyMTE2CWVzdGltYXRlZAlvbmVlaWdodGgMdGhyZWVlaWdodGhzC2ZpdmVlaWdodGhzDHNldmVuZWlnaHRocwd1bmlGRUZGB3VuaUZGRkMHdW5pRkZGRBNjaXJjdW1mbGV4dGlsZGVjb21iEmNpcmN1bWZsZXhob29rY29tYhNjaXJjdW1mbGV4Z3JhdmVjb21iE2NpcmN1bWZsZXhhY3V0ZWNvbWIOYnJldmVncmF2ZWNvbWIRY29tbWFhY2NlbnRyb3RhdGUGQS5zbWNwBkIuc21jcAZDLnNtY3AGRC5zbWNwBkUuc21jcAZGLnNtY3AGRy5zbWNwBkguc21jcAZJLnNtY3AGSi5zbWNwBksuc21jcAZMLnNtY3AGTS5zbWNwBk4uc21jcAZPLnNtY3AGUS5zbWNwBlIuc21jcAZTLnNtY3AGVC5zbWNwBlUuc21jcAZWLnNtY3AGVy5zbWNwBlguc21jcAZZLnNtY3AGWi5zbWNwDWJyZXZlaG9va2NvbWIOYnJldmVhY3V0ZWNvbWIIY3Jvc3NiYXIJcmluZ2FjdXRlCWRhc2lhb3hpYQ5icmV2ZXRpbGRlY29tYgtjeXJpbGxpY3RpYwxjeXJpbGxpY2hvb2sGUC5zbWNwBUsuYWx0D0dlcm1hbmRibHMuc21jcAd1bmkwMEFEB3VuaTAxMEEHdW5pMDEwQgd1bmkwMTIwB3VuaTAxMjELbmFwb3N0cm9waGUHdW5pMDIxOAd1bmkwMjE5B3VuaTAyMUEHdW5pMDIxQgd1bmkwMTYyDHVuaTAxNjIuc21jcAd1bmkwMTYzC0Rjcm9hdC5zbWNwCEV0aC5zbWNwCVRiYXIuc21jcAtBZ3JhdmUuc21jcAtBYWN1dGUuc21jcBBBY2lyY3VtZmxleC5zbWNwC0F0aWxkZS5zbWNwDkFkaWVyZXNpcy5zbWNwCkFyaW5nLnNtY3APQXJpbmdhY3V0ZS5zbWNwDUNjZWRpbGxhLnNtY3ALRWdyYXZlLnNtY3ALRWFjdXRlLnNtY3AQRWNpcmN1bWZsZXguc21jcA5FZGllcmVzaXMuc21jcAtJZ3JhdmUuc21jcAtJYWN1dGUuc21jcBBJY2lyY3VtZmxleC5zbWNwDklkaWVyZXNpcy5zbWNwC050aWxkZS5zbWNwC09ncmF2ZS5zbWNwC09hY3V0ZS5zbWNwEE9jaXJjdW1mbGV4LnNtY3ALT3RpbGRlLnNtY3AOT2RpZXJlc2lzLnNtY3ALVWdyYXZlLnNtY3ALVWFjdXRlLnNtY3AQVWNpcmN1bWZsZXguc21jcA5VZGllcmVzaXMuc21jcAtZYWN1dGUuc21jcAxBbWFjcm9uLnNtY3ALQWJyZXZlLnNtY3AMQW9nb25lay5zbWNwC0NhY3V0ZS5zbWNwEENjaXJjdW1mbGV4LnNtY3ALQ2Nhcm9uLnNtY3ALRGNhcm9uLnNtY3AMRW1hY3Jvbi5zbWNwC0VicmV2ZS5zbWNwD0Vkb3RhY2NlbnQuc21jcAxFb2dvbmVrLnNtY3ALRWNhcm9uLnNtY3AQR2NpcmN1bWZsZXguc21jcAtHYnJldmUuc21jcBFHY29tbWFhY2NlbnQuc21jcBBIY2lyY3VtZmxleC5zbWNwC0l0aWxkZS5zbWNwDEltYWNyb24uc21jcAtJYnJldmUuc21jcAxJb2dvbmVrLnNtY3APSWRvdGFjY2VudC5zbWNwEEpjaXJjdW1mbGV4LnNtY3ARS2NvbW1hYWNjZW50LnNtY3ALTGFjdXRlLnNtY3ARTGNvbW1hYWNjZW50LnNtY3ALTGNhcm9uLnNtY3AJTGRvdC5zbWNwC05hY3V0ZS5zbWNwEU5jb21tYWFjY2VudC5zbWNwC05jYXJvbi5zbWNwDE9tYWNyb24uc21jcAtPYnJldmUuc21jcBJPaHVuZ2FydW1sYXV0LnNtY3ALUmFjdXRlLnNtY3ARUmNvbW1hYWNjZW50LnNtY3ALUmNhcm9uLnNtY3ALU2FjdXRlLnNtY3AQU2NpcmN1bWZsZXguc21jcA1TY2VkaWxsYS5zbWNwC1NjYXJvbi5zbWNwC1RjYXJvbi5zbWNwC1V0aWxkZS5zbWNwDFVtYWNyb24uc21jcAtVYnJldmUuc21jcApVcmluZy5zbWNwElVodW5nYXJ1bWxhdXQuc21jcAxVb2dvbmVrLnNtY3AQV2NpcmN1bWZsZXguc21jcBBZY2lyY3VtZmxleC5zbWNwDllkaWVyZXNpcy5zbWNwC1phY3V0ZS5zbWNwD1pkb3RhY2NlbnQuc21jcAtaY2Fyb24uc21jcApBbHBoYXRvbm9zDEVwc2lsb250b25vcwhFdGF0b25vcwlJb3RhdG9ub3MMT21pY3JvbnRvbm9zDFVwc2lsb250b25vcwpPbWVnYXRvbm9zEWlvdGFkaWVyZXNpc3Rvbm9zBUFscGhhBEJldGEHRXBzaWxvbgRaZXRhA0V0YQRJb3RhBUthcHBhAk11Ak51B09taWNyb24DUmhvA1RhdQdVcHNpbG9uA0NoaQxJb3RhZGllcmVzaXMPVXBzaWxvbmRpZXJlc2lzCmFscGhhdG9ub3MMZXBzaWxvbnRvbm9zCGV0YXRvbm9zCWlvdGF0b25vcxR1cHNpbG9uZGllcmVzaXN0b25vcwVrYXBwYQdvbWljcm9uB3VuaTAzQkMCbnUDY2hpDGlvdGFkaWVyZXNpcw91cHNpbG9uZGllcmVzaXMMb21pY3JvbnRvbm9zDHVwc2lsb250b25vcwpvbWVnYXRvbm9zB3VuaTA0MDEHdW5pMDQwMwd1bmkwNDA1B3VuaTA0MDYHdW5pMDQwNwd1bmkwNDA4B3VuaTA0MUEHdW5pMDQwQwd1bmkwNDBFB3VuaTA0MTAHdW5pMDQxMgd1bmkwNDEzB3VuaTA0MTUHdW5pMDQxOQd1bmkwNDFDB3VuaTA0MUQHdW5pMDQxRQd1bmkwNDFGB3VuaTA0MjAHdW5pMDQyMQd1bmkwNDIyB3VuaTA0MjQHdW5pMDQyNQd1bmkwNDMwB3VuaTA0MzUHdW5pMDQzOQd1bmkwNDNFB3VuaTA0NDAHdW5pMDQ0MQd1bmkwNDQzB3VuaTA0NDUHdW5pMDQ1MQd1bmkwNDUzB3VuaTA0NTUHdW5pMDQ1Ngd1bmkwNDU3B3VuaTA0NTgHdW5pMDQ1Qwd1bmkwNDVFCWV4Y2xhbWRibAd1bmkwMUYwB3VuaTAyQkMHdW5pMUUzRQd1bmkxRTNGB3VuaTFFMDAHdW5pMUUwMQd1bmkxRjREB3VuaTA0MDAHdW5pMDQwRAd1bmkwNDUwB3VuaTA0NUQHdW5pMDQ3MAd1bmkwNDcxB3VuaTA0NzYHdW5pMDQ3Nwd1bmkwNDk4B3VuaTA0OTkHdW5pMDRBQQd1bmkwNEFCB3VuaTA0QUUHdW5pMDRBRgd1bmkwNEMwB3VuaTA0QzEHdW5pMDRDMgd1bmkwNENGB3VuaTA0RDAHdW5pMDREMQd1bmkwNEQyB3VuaTA0RDMHdW5pMDRENAd1bmkwNEQ1B3VuaTA0RDYHdW5pMDRENwd1bmkwNERBB3VuaTA0RDkHdW5pMDREQgd1bmkwNERDB3VuaTA0REQHdW5pMDRERQd1bmkwNERGB3VuaTA0RTIHdW5pMDRFMwd1bmkwNEU0B3VuaTA0RTUHdW5pMDRFNgd1bmkwNEU3B3VuaTA0RTgHdW5pMDRFOQd1bmkwNEVBB3VuaTA0RUIHdW5pMDRFQwd1bmkwNEVEB3VuaTA0RUUHdW5pMDRFRgd1bmkwNEYwB3VuaTA0RjEHdW5pMDRGMgd1bmkwNEYzB3VuaTA0RjQHdW5pMDRGNQd1bmkwNEY4B3VuaTA0RjkHdW5pMDRGQwd1bmkwNEZEB3VuaTA1MDEHdW5pMDUxMgd1bmkwNTEzB3VuaTFFQTAHdW5pMUVBMQd1bmkxRUEyB3VuaTFFQTMHdW5pMUVBNAd1bmkxRUE1B3VuaTFFQTYHdW5pMUVBNwd1bmkxRUE4B3VuaTFFQTkHdW5pMUVBQQd1bmkxRUFCB3VuaTFFQUMHdW5pMUVBRAd1bmkxRUFFB3VuaTFFQUYHdW5pMUVCMAd1bmkxRUIxB3VuaTFFQjIHdW5pMUVCMwd1bmkxRUI0B3VuaTFFQjUHdW5pMUVCNgd1bmkxRUI3B3VuaTFFQjgHdW5pMUVCOQd1bmkxRUJBB3VuaTFFQkIHdW5pMUVCQwd1bmkxRUJEB3VuaTFFQkUHdW5pMUVCRgd1bmkxRUMwB3VuaTFFQzEHdW5pMUVDMgd1bmkxRUMzB3VuaTFFQzQHdW5pMUVDNQd1bmkxRUM2B3VuaTFFQzcHdW5pMUVDOAd1bmkxRUM5B3VuaTFFQ0EHdW5pMUVDQgd1bmkxRUNDB3VuaTFFQ0QHdW5pMUVDRQd1bmkxRUNGB3VuaTFFRDAHdW5pMUVEMQd1bmkxRUQyB3VuaTFFRDMHdW5pMUVENAd1bmkxRUQ1B3VuaTFFRDYHdW5pMUVENwd1bmkxRUQ4B3VuaTFFRDkHdW5pMUVEQQd1bmkxRURCB3VuaTFFREMHdW5pMUVERAd1bmkxRURFB3VuaTFFREYHdW5pMUVFMAd1bmkxRUUxB3VuaTFFRTIHdW5pMUVFMwd1bmkxRUU0B3VuaTFFRTUHdW5pMUVFNgd1bmkxRUU3B3VuaTFFRTgHdW5pMUVFOQd1bmkxRUVBB3VuaTFFRUIHdW5pMUVFQwd1bmkxRUVEB3VuaTFFRUUHdW5pMUVFRgd1bmkxRUYwB3VuaTFFRjEHdW5pMUVGNAd1bmkxRUY1B3VuaTFFRjYHdW5pMUVGNwd1bmkxRUY4B3VuaTFFRjkHdW5pMjBBQgd1bmkwNDlBB3VuaTA0OUIHdW5pMDRBMgd1bmkwNEEzB3VuaTA0QUMHdW5pMDRBRAd1bmkwNEIyB3VuaTA0QjMHdW5pMDRCNgd1bmkwNEI3B3VuaTA0Q0IHdW5pMDRDQwd1bmkwNEY2B3VuaTA0RjcHdW5pMDQ5Ngd1bmkwNDk3B3VuaTA0QkUHdW5pMDRCRgd1bmkwNEJCB3VuaTA0OEQHdW5pMDQ4Qwd1bmkwNDYyB3VuaTA0OTIHdW5pMDQ5Mwd1bmkwNDlFB3VuaTA0OUYHdW5pMDQ4QQd1bmkwNDhCB3VuaTA0QzkHdW5pMDRDQQd1bmkwNENEB3VuaTA0Q0UHdW5pMDRDNQd1bmkwNEM2B3VuaTA0QjAHdW5pMDRCMQd1bmkwNEZFB3VuaTA0RkYHdW5pMDUxMQd1bmkyMDE1AAEAAf//AA8AAQAAAAoAMAA+AARERkxUABpjeXJsABpncmVrABpsYXRuABoABAAAAAD//wABAAAAAXNtY3AACAAAAAEAAAABAAQAAQAAAAEACAACAb4A3AJPAlACUQJSAlMCVAJVAlYCVwJYAlkCWgJbAlwCXQJwAl4CXwJgAmECYgJjAmQCZQJmAmcCTwJQAlECUgJTAlQCVQJWAlcCWAJZAloCWwJcAl0CcAJeAl8CYAJhAmICYwJkAmUCZgJnAoICcgKFAqAChgKIAoQCnwKhAokCigKHAqICpAKLAqMCpQKBAo0CpwKqAo4CjwKoAowCpgKpAoICrAKrAq0CrgKRArECkgKTArMCkAKwArICrwK0ArUCtgK4ArcCuQK6ArwCuwKUApYCvgKXApkClQK/Ar0CmALAAsICwQLDAsYCxQLEAoMCxwKbAsoCnAKdApoCzALJAs0CywLIAs4CngLPAtAC0QLTAtIChQKgAoYCiAKEAp8CoQKJAooChwKiAqQCiwKjAqUCgQKNAqcCqgKOAo8CqAKMAqYCqQKsAqsCrQKuApECsQKSApMCkAKwArICrwK0ArUCtgK4ArcCuQK6ArwCuwKUApYCvgKXApkClQK/Ar0CmALAAsICwQLDAsYCxQLEAoMCxwKbAsoCnAKdApoCzALJAs0CywLIAs4CngLPAtAC0QLTAtICfwJ/AAIAGgACADUAAABMAEwANABQAFAANQCeAKcANgCpALYAQAC4ALwATgC+AM0AUwDPANcAYwDZANoAbADdAOsAbgDtAPEAfQDzAPMAggD2APgAgwD6AQYAhgEIARUAkwEXARoAoQEcASoApQEsATQAtAE2ATcAvQE6AUgAvwFKAU4AzgFQAVAA0wFTAVUA1AFXAVkA1wJ+An4A2gKAAoAA2wABAAEACAACAAAAFAACAAAAJAACd2dodAEAAABpdGFsAQsAAQAEABAAAQAAAAABDwH0AAAAAwABAAIBEQAAAAAAAQAA) +@page { + size: auto; + margin: 0mm; /* remove margin in printer settings */ } * { box-sizing: border-box; - margin: 0px; - + + margin: 0; + padding: 0; + margin-block-start: 0; + margin-block-end: 0; + font-family: -apple-system, Roboto; - font-style: normal; - font-weight: 400; - color: #1A2733; } body { - width: 840px; - margin: auto; - padding: 12px; - background-color: #FFFFFF; -} - -h1 { - font-size: 20px; - font-weight: 600; - line-height: 32px; -} - -h2 { - margin-top: 24px; - margin-bottom: 8px; - font-size: 20px; - font-weight: 500; - line-height: 32px; -} - -h3 { - margin-top: 24px; - margin-bottom: 8px; - font-size: 16px; - line-height: 24px; - font-weight: 500; -} - -h4 { - font-size: 14px; - line-height: 24px; -} - -p { - margin-bottom: 12px; - line-height: 24px; - letter-spacing: 0.01em; -} - -a { - font-weight: 500; - text-decoration: none; - color: #2474cd; + width: 480px; } strong { font-weight: 500; } -.logo { - margin-bottom: 24px; -} - header { display: flex; - flex-direction: row; - margin-bottom: 24px; + justify-content: space-between; + padding: 20px 16px; + background-color: #F7FBFF; } -header .title { - flex-grow: 1; +h1 { + margin: 0; + font-family: -apple-system, Roboto; + font-weight: 500; + font-size: 24px; + line-height: 30px; + color: #182449; } -header date { - font-size: 12px; - font-style: italic; - color: #57656F; +h2 { + color: #182449; } -header .verification-code { - text-align: right; +h3 { + color: #182449; } -header .verification-code code { - font-family: Menlo-Regular, Roboto Mono; - font-size: 16px; - line-height: 24px; +header h2 { + margin: 3px 0 0 0; + font-family: Menlo, Roboto Mono; + font-weight: 500; + font-size: 18px; + line-height: 27px; + color: #576580; + text-transform: uppercase; } -section h1 { +a { + color: #337cd0; +} + +.backup { + margin: 24px 16px 0 16px; + background-color: #DFECFB; +} + +.backup .intro { + display: flex; + padding: 16px 16px 16px 0; +} + +.backup h1 { + margin-top: 16px; + margin-bottom: 8px; + font-weight: 500; + font-size: 32px; + line-height: 32px; line-height: 32px; } -section p { - color: #57656F; +.backup h2 { + font-size: 15px; + font-weight: 400; + font-size: 15px; line-height: 24px; + color: #57656F; } -.data { - padding: 16px; - border: 1px solid #C8D2D9; - border-radius: 4px; +.backup h2 strong { + color: #182449; +} - font-family: Menlo-Regular, Roboto Mono; - font-style: normal; - font-weight: normal; - font-size: 10px; - line-height: 16px; +.backup h3 { + margin-bottom: 8px; + font-weight: 500; + font-size: 18px; + line-height: 24px; + text-transform: uppercase; letter-spacing: 0.05em; - word-break: break-all; - - background: #F5F6F7; } -.key-placeholder { - font-weight: bold; +.backup svg { + margin: 8px 4px 0; +} + +.backup .key { + padding: 32px 16px 24px 16px; + margin: 0 4px 4px 4px; + background-color: white; +} + +.backup .key p { + font-family: Menlo, Roboto Mono; + font-weight: 400; + font-size: 13px; + word-wrap: break-word; + line-height: 24px; + color: #57656F; +} + +.backup .date { + padding: 12px 0; + font-size: 13px; + line-height: 24px; + text-align: center; + letter-spacing: 0.05em; + text-transform: uppercase; + color: #57656F; +} + +.backup .date date { + font-weight: 500; + color: #182449; +} + +section { + margin-top: 40px; + padding: 16px; +} + +section h2 { + margin-top: 24px; + font-weight: 500; + font-size: 20px; + line-height: 32px; +} + +section h3 { + font-weight: 500; + font-size: 20px; + line-height: 32px; + color: #182449; +} + +section p { + margin-top: 8px; + font-weight: normal; + font-size: 16px; + line-height: 24px; + color: #576580; +} + +.instructions .item { + display: flex; + margin-top: 32px; +} + +.instructions .item .number-box { + margin-right: 16px; + padding-top: 6px; +} + +.instructions .item .number { + width: 20px; + border-radius: 50%; + text-align: center; + font-weight: 500; + font-size: 14px; + line-height: 20px; + background: #2474CD; + color: #ffffff; +} + +.help { + display: flex; + padding: 32px 16px 32px 0; + background: #F6F9FF; +} + +.help svg { + margin: 0 8px; +} + +.descriptors { + margin: 16px 0; + padding: 16px; + font-family: Menlo, Roboto Mono; + font-weight: 500; + font-size: 9px; + line-height: 240%; + letter-spacing: 1px; + list-style-type: none; + background: #F6F9FF; + color: #576580; +} + +.descriptors .f { + color: #447BEF; +} + +.descriptors .fp { + color: #d74a41; +} + +.descriptors .checksum { + color: #a42fa2; } @media print { diff --git a/vendor/github.com/muun/libwallet/emergencykit/descriptors.go b/vendor/github.com/muun/libwallet/emergencykit/descriptors.go new file mode 100644 index 0000000..21d207f --- /dev/null +++ b/vendor/github.com/muun/libwallet/emergencykit/descriptors.go @@ -0,0 +1,171 @@ +package emergencykit + +import ( + "fmt" + "strings" +) + +type DescriptorsData struct { + FirstFingerprint string + SecondFingerprint string +} + +// Output descriptors shown in the PDF do not include legacy descriptors no longer in use. We leave +// the decision of whether to scan them to the Recovery Tool. +var descriptorFormats = []string{ + "sh(wsh(multi(2, %s/1'/1'/0/*, %s/1'/1'/0/*)))", // V3 change + "sh(wsh(multi(2, %s/1'/1'/1/*, %s/1'/1'/1/*)))", // V3 external + "wsh(multi(2, %s/1'/1'/0/*, %s/1'/1'/0/*))", // V4 change + "wsh(multi(2, %s/1'/1'/1/*, %s/1'/1'/1/*))", // V4 external +} + +// GetDescriptors returns an array of raw output descriptors. +func GetDescriptors(data *DescriptorsData) []string { + var descriptors []string + + for _, descriptorFormat := range descriptorFormats { + descriptor := fmt.Sprintf(descriptorFormat, data.FirstFingerprint, data.SecondFingerprint) + checksum := calculateChecksum(descriptor) + + descriptors = append(descriptors, descriptor+"#"+checksum) + } + + return descriptors +} + +// GetDescriptorsHTML returns the HTML for the output descriptor list in the Emergency Kit. +func GetDescriptorsHTML(data *DescriptorsData) string { + descriptors := GetDescriptors(data) + + var itemsHTML []string + + for _, descriptor := range descriptors { + descriptor, checksum := splitChecksum(descriptor) + + html := descriptor + + // Replace script type expressions (parenthesis in match prevent replacing the "sh" in "wsh") + html = strings.ReplaceAll(html, "wsh(", renderScriptType("wsh")+"(") + html = strings.ReplaceAll(html, "sh(", renderScriptType("sh")+"(") + html = strings.ReplaceAll(html, "multi(", renderScriptType("multi")+"(") + + // Replace fingerprint expressions: + html = strings.ReplaceAll(html, data.FirstFingerprint, renderFingerprint(data.FirstFingerprint)) + html = strings.ReplaceAll(html, data.SecondFingerprint, renderFingerprint(data.SecondFingerprint)) + + // Add checksum and wrap everything: + html += renderChecksum(checksum) + html = renderItem(html) + + itemsHTML = append(itemsHTML, html) + } + + return renderList(itemsHTML) +} + +func renderList(itemsHTML []string) string { + return fmt.Sprintf(`
    %s
`, strings.Join(itemsHTML, "\n")) +} + +func renderItem(innerHTML string) string { + return fmt.Sprintf(`
  • %s
  • `, innerHTML) +} + +func renderScriptType(scriptType string) string { + return fmt.Sprintf(`%s`, scriptType) +} + +func renderFingerprint(fingerprint string) string { + return fmt.Sprintf(`%s`, fingerprint) +} + +func renderChecksum(checksum string) string { + return fmt.Sprintf(`#%s`, checksum) +} + +func splitChecksum(descriptor string) (string, string) { + parts := strings.Split(descriptor, "#") + + if len(parts) == 1 { + return parts[0], "" + } + + return parts[0], parts[1] +} + +// ------------------------------------------------------------------------------------------------- +// WARNING: +// Below this point, you may find only fear and confusion. + +// I translated the code for computing checksums from the original C++ in the bitcoind source, +// making a few adjustments for language differences. It's a specialized algorithm for the domain of +// output descriptors, and it uses the same primitives as the bech32 encoding. + +var inputCharset = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ " +var checksumCharset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" + +func calculateChecksum(desc string) string { + var c uint64 = 1 + var cls int = 0 + var clscount int = 0 + + for _, ch := range desc { + pos := strings.IndexRune(inputCharset, ch) + + if pos == -1 { + return "" + } + + c = polyMod(c, pos&31) + cls = cls*3 + (pos >> 5) + + clscount++ + if clscount == 3 { + c = polyMod(c, cls) + cls = 0 + clscount = 0 + } + } + + if clscount > 0 { + c = polyMod(c, cls) + } + + for i := 0; i < 8; i++ { + c = polyMod(c, 0) + } + + c ^= 1 + + ret := make([]byte, 8) + for i := 0; i < 8; i++ { + ret[i] = checksumCharset[(c>>(5*(7-i)))&31] + } + + return string(ret) +} + +func polyMod(c uint64, intVal int) uint64 { + val := uint64(intVal) + + c0 := c >> 35 + c = ((c & 0x7ffffffff) << 5) ^ val + + if c0&1 != 0 { + c ^= 0xf5dee51989 + } + if c0&2 != 0 { + c ^= 0xa9fdca3312 + } + if c0&4 != 0 { + c ^= 0x1bab10e32d + } + if c0&8 != 0 { + c ^= 0x3706b1677a + } + if c0&16 != 0 { + c ^= 0x644d626ffd + } + + return c +} diff --git a/vendor/github.com/muun/libwallet/emergencykit/emergencykit.go b/vendor/github.com/muun/libwallet/emergencykit/emergencykit.go index 3b8b78b..1c9642a 100644 --- a/vendor/github.com/muun/libwallet/emergencykit/emergencykit.go +++ b/vendor/github.com/muun/libwallet/emergencykit/emergencykit.go @@ -2,8 +2,9 @@ package emergencykit import ( "bytes" - "crypto/rand" + "crypto/sha256" "fmt" + "strconv" "text/template" "time" ) @@ -11,7 +12,9 @@ import ( // Input struct to fill the PDF type Input struct { FirstEncryptedKey string + FirstFingerprint string SecondEncryptedKey string + SecondFingerprint string } // Output with the html as string and the verification code @@ -20,24 +23,57 @@ type Output struct { VerificationCode string } +var spanishMonthNames = []string{ + "Enero", + "Febrero", + "Marzo", + "Abril", + "Mayo", + "Junio", + "Julio", + "Agosto", + "Septiembre", + "Octubre", + "Noviembre", + "Diciembre", +} + // GenerateHTML returns the translated emergency kit html as a string along with the verification code. func GenerateHTML(params *Input, lang string) (*Output, error) { - verificationCode := randomCode(6) + verificationCode := generateDeterministicCode(params) + // Render output descriptors: + var descriptors string + + if params.hasFingerprints() { + descriptors = GetDescriptorsHTML(&DescriptorsData{ + FirstFingerprint: params.FirstFingerprint, + SecondFingerprint: params.SecondFingerprint, + }) + } + + // Render page body: content, err := render("EmergencyKitContent", lang, &contentData{ + // Externally provided: FirstEncryptedKey: params.FirstEncryptedKey, SecondEncryptedKey: params.SecondEncryptedKey, - VerificationCode: verificationCode, - // Careful: do not change these format values. See this doc for more info: https://golang.org/pkg/time/#pkg-constants - CurrentDate: time.Now().Format("2006/01/02"), // Format date to YYYY/MM/DD + + // Computed by us: + VerificationCode: verificationCode, + CurrentDate: formatDate(time.Now(), lang), + Descriptors: descriptors, + + // Template pieces separated for reuse: + IconHelp: iconHelp, + IconPadlock: iconPadlock, }) if err != nil { return nil, fmt.Errorf("failed to render EmergencyKitContent template: %w", err) } + // Render complete HTML page: page, err := render("EmergencyKitPage", lang, &pageData{ Css: css, - Logo: logo, Content: content, }) if err != nil { @@ -50,17 +86,40 @@ func GenerateHTML(params *Input, lang string) (*Output, error) { }, nil } -func randomCode(length int) string { - result := make([]byte, length) - _, err := rand.Read(result) - if err != nil { - panic(err) +func formatDate(t time.Time, lang string) string { + if lang == "en" { + return t.Format("January 2, 2006") + + } else { + // Golang has no i18n facilities, so we do our own formatting. + year, month, day := t.Date() + monthName := spanishMonthNames[month-1] + + return fmt.Sprintf("%d de %s, %d", day, monthName, year) } - charset := "0123456789" - for i := 0; i < length; i++ { - result[i] = charset[int(result[i])%len(charset)] +} + +func generateDeterministicCode(params *Input) string { + // NOTE: + // This function creates a stable verification code given the inputs to render the Emergency Kit. For now, the + // implementation relies exclusively on the SecondEncryptedKey, which is the Muun key. This is obviously not ideal, + // since we're both dropping part of the input and introducing the assumption that the Muun key will always be + // rendered second -- but it compensates for a problem with one of our clients that causes the user key serialization + // to be recreated each time the kit is rendered (making this deterministic approach useless). + + // Create a deterministic serialization of the input: + inputMaterial := params.SecondEncryptedKey + + // Compute a cryptographically secure hash of the material (critical, these are keys): + inputHash := sha256.Sum256([]byte(inputMaterial)) + + // Extract a verification code from the hash (doesn't matter if we discard bytes): + var code string + for _, b := range inputHash[:6] { + code += strconv.Itoa(int(b) % 10) } - return string(result) + + return code } func render(name, language string, data interface{}) (string, error) { @@ -80,12 +139,18 @@ func getContent(name string, language string) string { switch name { case "EmergencyKitPage": return page + case "EmergencyKitContent": if language == "es" { return contentES } return contentEN + default: panic("could not find template with name: " + name) } } + +func (i *Input) hasFingerprints() bool { + return i.FirstFingerprint != "" && i.SecondFingerprint != "" +} diff --git a/vendor/github.com/muun/libwallet/emergencykit/metadata.go b/vendor/github.com/muun/libwallet/emergencykit/metadata.go new file mode 100644 index 0000000..520b36a --- /dev/null +++ b/vendor/github.com/muun/libwallet/emergencykit/metadata.go @@ -0,0 +1,145 @@ +package emergencykit + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/pdfcpu/pdfcpu/pkg/api" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" +) + +// MetadataReader can extract the metadata file from a PDF. +type MetadataReader struct { + SrcFile string +} + +// MetadataWriter can add the metadata file to a PDF. +type MetadataWriter struct { + SrcFile string + DstFile string +} + +// Metadata holds the machine-readable data for an Emergency Kit. +type Metadata struct { + Version int `json:"version"` + BirthdayBlock int `json:"birthdayBlock"` + EncryptedKeys []*MetadataKey `json:"encryptedKeys"` + OutputDescriptors []string `json:"outputDescriptors"` +} + +// MetadataKey holds an entry in the Metadata key array. +type MetadataKey struct { + DhPubKey string `json:"dhPubKey"` + EncryptedPrivKey string `json:"encryptedPrivKey"` + Salt string `json:"salt"` +} + +// The name for the embedded metadata file in the PDF document: +const metadataName = "metadata.json" + +// Default configuration values copied from pdfcpu source code (some values are irrelevant to us): +var pdfConfig = &pdfcpu.Configuration{ + Reader15: true, + DecodeAllStreams: false, + ValidationMode: pdfcpu.ValidationRelaxed, + Eol: pdfcpu.EolLF, + WriteObjectStream: true, + WriteXRefStream: true, + EncryptUsingAES: true, + EncryptKeyLength: 256, + Permissions: pdfcpu.PermissionsNone, +} + +// HasMetadata returns whether the metadata is present (and alone) in SrcFile. +func (mr *MetadataReader) HasMetadata() (bool, error) { + fs, err := api.ListAttachmentsFile(mr.SrcFile, pdfConfig) + if err != nil { + return false, fmt.Errorf("HasMetadata failed to list attachments: %w", err) + } + + return len(fs) == 1 && fs[0] == metadataName, nil +} + +// ReadMetadata returns the deserialized metadata file embedded in the SrcFile PDF. +func (mr *MetadataReader) ReadMetadata() (*Metadata, error) { + // NOTE: + // Due to library constraints, this makes use of a temporary directory in the default system temp + // location, which for the Recovery Tool will always be accessible. If we eventually want to read + // this metadata in mobile clients, we'll need the caller to provide a directory. + + // Before we begin, verify that the metadata file is embedded: + hasMetadata, err := mr.HasMetadata() + if err != nil { + return nil, fmt.Errorf("ReadMetadata failed to check for existence: %w", err) + } + if !hasMetadata { + return nil, fmt.Errorf("ReadMetadata didn't find %s (or found more) in this PDF", metadataName) + } + + // Create the temporary directory, with a deferred call to clean up: + tmpDir, err := ioutil.TempDir("", "ek-metadata-*") + if err != nil { + return nil, fmt.Errorf("ReadMetadata failed to create a temporary directory") + } + + defer os.RemoveAll(tmpDir) + + // Extract the embedded attachment from the PDF into that directory: + err = api.ExtractAttachmentsFile(mr.SrcFile, tmpDir, []string{metadataName}, pdfConfig) + if err != nil { + return nil, fmt.Errorf("ReadMetadata failed to extract attachment: %w", err) + } + + // Read the contents of the file: + metadataBytes, err := ioutil.ReadFile(filepath.Join(tmpDir, metadataName)) + if err != nil { + return nil, fmt.Errorf("ReadMetadata failed to read the extracted file: %w", err) + } + + // Deserialize the metadata: + var metadata Metadata + err = json.Unmarshal(metadataBytes, &metadata) + if err != nil { + return nil, fmt.Errorf("ReadMetadata failed to unmarshal %s: %w", string(metadataBytes), err) + } + + // Done we are! + return &metadata, nil +} + +// WriteMetadata creates a copy of SrcFile with attached JSON metadata into DstFile. +func (mw *MetadataWriter) WriteMetadata(metadata *Metadata) error { + // NOTE: + // Due to library constraints, this makes use of a temporary file placed in the same directory as + // `SrcFile`, which is assumed to be writable. This is a much safer bet than attempting to pick a + // location for temporary files ourselves. + + // Decide the location of the temporary file: + srcDir := filepath.Dir(mw.SrcFile) + tmpFile := filepath.Join(srcDir, metadataName) + + // Serialize the metadata: + metadataBytes, err := json.Marshal(metadata) + if err != nil { + return fmt.Errorf("WriteMetadata failed to marshal: %w", err) + } + + // Write to the temporary file, with a deferred call to clean up: + err = ioutil.WriteFile(tmpFile, metadataBytes, os.FileMode(0600)) + if err != nil { + return fmt.Errorf("WriteMetadata failed to write a temporary file: %w", err) + } + + defer os.Remove(tmpFile) + + // Add the attachment, returning potential errors: + err = api.AddAttachmentsFile(mw.SrcFile, mw.DstFile, []string{tmpFile}, false, pdfConfig) + if err != nil { + return fmt.Errorf("WriteMetadata failed to add attachment file %s: %w", tmpFile, err) + } + + return nil +} diff --git a/vendor/github.com/muun/libwallet/encrypt.go b/vendor/github.com/muun/libwallet/encrypt.go index bb11a5d..808fcf2 100644 --- a/vendor/github.com/muun/libwallet/encrypt.go +++ b/vendor/github.com/muun/libwallet/encrypt.go @@ -7,6 +7,8 @@ import ( "crypto/rand" "crypto/sha256" "encoding/binary" + "errors" + "fmt" "io" "math" "math/big" @@ -15,7 +17,6 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcutil/base58" - "github.com/pkg/errors" ) const serializedPublicKeyLength = btcec.PubKeyBytesLenCompressed @@ -47,18 +48,18 @@ type hdPubKeyEncrypter struct { func addVariableBytes(writer io.Writer, data []byte) error { if len(data) > math.MaxUint16 { - return errors.Errorf("data length can't exceeed %v", math.MaxUint16) + return fmt.Errorf("data length can't exceeed %v", math.MaxUint16) } dataLen := uint16(len(data)) err := binary.Write(writer, binary.BigEndian, &dataLen) if err != nil { - return errors.Wrapf(err, "failed to write var bytes len") + return fmt.Errorf("failed to write var bytes len: %w", err) } n, err := writer.Write(data) if err != nil || n != len(data) { - return errors.Errorf("failed to write var bytes") + return errors.New("failed to write var bytes") } return nil @@ -88,12 +89,12 @@ func (e *hdPubKeyEncrypter) Encrypt(payload []byte) (string, error) { signingKey, err := e.senderKey.key.ECPrivKey() if err != nil { - return "", errors.Wrapf(err, "Encrypt: failed to extract signing key") + return "", fmt.Errorf("Encrypt: failed to extract signing key: %w", err) } encryptionKey, err := e.receiverKey.key.ECPubKey() if err != nil { - return "", errors.Wrapf(err, "Encrypt: failed to extract pub key") + return "", fmt.Errorf("Encrypt: failed to extract pub key: %w", err) } // Sign "payload || encryptionKey" to protect against payload reuse by 3rd parties @@ -103,34 +104,34 @@ func (e *hdPubKeyEncrypter) Encrypt(payload []byte) (string, error) { hash := sha256.Sum256(signaturePayload) senderSignature, err := btcec.SignCompact(btcec.S256(), signingKey, hash[:], false) if err != nil { - return "", errors.Wrapf(err, "Encrypt: failed to sign payload") + return "", fmt.Errorf("Encrypt: failed to sign payload: %w", err) } // plaintext is "senderSignature || payload" plaintext := bytes.NewBuffer(make([]byte, 0, 2+len(payload)+2+len(senderSignature))) err = addVariableBytes(plaintext, senderSignature) if err != nil { - return "", errors.Wrapf(err, "Encrypter: failed to add senderSignature") + return "", fmt.Errorf("Encrypter: failed to add senderSignature: %w", err) } err = addVariableBytes(plaintext, payload) if err != nil { - return "", errors.Wrapf(err, "Encrypter: failed to add payload") + return "", fmt.Errorf("Encrypter: failed to add payload: %w", err) } pubEph, sharedSecret, err := generateSharedEncryptionSecretForAES(encryptionKey) if err != nil { - return "", errors.Wrapf(err, "Encrypt: failed to generate shared encryption key") + return "", fmt.Errorf("Encrypt: failed to generate shared encryption key: %w", err) } blockCipher, err := aes.NewCipher(sharedSecret) if err != nil { - return "", errors.Wrapf(err, "Encrypt: new aes failed") + return "", fmt.Errorf("Encrypt: new aes failed: %w", err) } gcm, err := cipher.NewGCM(blockCipher) if err != nil { - return "", errors.Wrapf(err, "Encrypt: new gcm failed") + return "", fmt.Errorf("Encrypt: new gcm failed: %w", err) } nonce := randomBytes(gcm.NonceSize()) @@ -143,13 +144,13 @@ func (e *hdPubKeyEncrypter) Encrypt(payload []byte) (string, error) { err = addVariableBytes(result, []byte(e.receiverKey.Path)) if err != nil { - return "", errors.Wrapf(err, "Encrypt: failed to add receiver path") + return "", fmt.Errorf("Encrypt: failed to add receiver path: %w", err) } nonceLen := uint16(len(nonce)) err = binary.Write(result, binary.BigEndian, &nonceLen) if err != nil { - return "", errors.Wrapf(err, "Encrypt: failed to add nonce len") + return "", fmt.Errorf("Encrypt: failed to add nonce len: %w", err) } ciphertext := gcm.Seal(nil, nonce, plaintext.Bytes(), result.Bytes()) @@ -157,12 +158,12 @@ func (e *hdPubKeyEncrypter) Encrypt(payload []byte) (string, error) { // result is "additionalData || nonce || ciphertext" n, err := result.Write(nonce) if err != nil || n != len(nonce) { - return "", errors.Errorf("Encrypt: failed to add nonce") + return "", errors.New("Encrypt: failed to add nonce") } n, err = result.Write(ciphertext) if err != nil || n != len(ciphertext) { - return "", errors.Errorf("Encrypt: failed to add ciphertext") + return "", errors.New("Encrypt: failed to add ciphertext") } return base58.Encode(result.Bytes()), nil @@ -185,13 +186,13 @@ func extractVariableBytes(reader *bytes.Reader, limit int) ([]byte, error) { var len uint16 err := binary.Read(reader, binary.BigEndian, &len) if err != nil || int(len) > limit || int(len) > reader.Len() { - return nil, errors.Errorf("failed to read byte array len") + return nil, errors.New("failed to read byte array len") } result := make([]byte, len) n, err := reader.Read(result) if err != nil || n != int(len) { - return nil, errors.Errorf("failed to extract byte array") + return nil, errors.New("failed to extract byte array") } return result, nil @@ -210,22 +211,22 @@ func (d *hdPrivKeyDecrypter) Decrypt(payload string) ([]byte, error) { reader := bytes.NewReader(decoded) version, err := reader.ReadByte() if err != nil { - return nil, errors.Wrapf(err, "Decrypt: failed to read version byte") + return nil, fmt.Errorf("Decrypt: failed to read version byte: %w", err) } if version != PKEncryptionVersion { - return nil, errors.Errorf("Decrypt: found key version %v, expected %v", + return nil, fmt.Errorf("Decrypt: found key version %v, expected %v", version, PKEncryptionVersion) } rawPubEph := make([]byte, serializedPublicKeyLength) n, err := reader.Read(rawPubEph) if err != nil || n != serializedPublicKeyLength { - return nil, errors.Errorf("Decrypt: failed to read pubeph") + return nil, errors.New("Decrypt: failed to read pubeph") } receiverPath, err := extractVariableString(reader, maxDerivationPathLen) if err != nil { - return nil, errors.Wrapf(err, "Decrypt: failed to extract receiver path") + return nil, fmt.Errorf("Decrypt: failed to extract receiver path: %w", err) } // additionalDataSize is Whatever I've read so far plus two bytes for the nonce len @@ -234,24 +235,24 @@ func (d *hdPrivKeyDecrypter) Decrypt(payload string) ([]byte, error) { minCiphertextLen := 2 // an empty sig with no plaintext nonce, err := extractVariableBytes(reader, reader.Len()-minCiphertextLen) if err != nil || len(nonce) < minNonceLen { - return nil, errors.Errorf("Decrypt: failed to read nonce") + return nil, errors.New("Decrypt: failed to read nonce") } // What's left is the ciphertext ciphertext := make([]byte, reader.Len()) _, err = reader.Read(ciphertext) if err != nil { - return nil, errors.Wrapf(err, "Decrypt: failed to read ciphertext") + return nil, fmt.Errorf("Decrypt: failed to read ciphertext: %w", err) } receiverKey, err := d.receiverKey.DeriveTo(receiverPath) if err != nil { - return nil, errors.Wrapf(err, "Decrypt: failed to derive receiver key to path %v", receiverPath) + return nil, fmt.Errorf("Decrypt: failed to derive receiver key to path %v: %w", receiverPath, err) } encryptionKey, err := receiverKey.key.ECPrivKey() if err != nil { - return nil, errors.Wrapf(err, "Decrypt: failed to extract encryption key") + return nil, fmt.Errorf("Decrypt: failed to extract encryption key: %w", err) } var verificationKey *btcec.PublicKey @@ -259,7 +260,7 @@ func (d *hdPrivKeyDecrypter) Decrypt(payload string) ([]byte, error) { // Use the derived receiver key if the sender key is not provided verificationKey, err = receiverKey.PublicKey().key.ECPubKey() if err != nil { - return nil, errors.Wrapf(err, "Decrypt: failed to extract verification key") + return nil, fmt.Errorf("Decrypt: failed to extract verification key: %w", err) } } else if d.senderKey != nil { verificationKey = d.senderKey.key @@ -267,34 +268,34 @@ func (d *hdPrivKeyDecrypter) Decrypt(payload string) ([]byte, error) { sharedSecret, err := recoverSharedEncryptionSecretForAES(encryptionKey, rawPubEph) if err != nil { - return nil, errors.Wrapf(err, "Decrypt: failed to recover shared secret") + return nil, fmt.Errorf("Decrypt: failed to recover shared secret: %w", err) } blockCipher, err := aes.NewCipher(sharedSecret) if err != nil { - return nil, errors.Wrapf(err, "Decrypt: new aes failed") + return nil, fmt.Errorf("Decrypt: new aes failed: %w", err) } gcm, err := cipher.NewGCMWithNonceSize(blockCipher, len(nonce)) if err != nil { - return nil, errors.Wrapf(err, "Decrypt: new gcm failed") + return nil, fmt.Errorf("Decrypt: new gcm failed: %w", err) } plaintext, err := gcm.Open(nil, nonce, ciphertext, decoded[:additionalDataSize]) if err != nil { - return nil, errors.Wrapf(err, "Decrypt: AEAD failed") + return nil, fmt.Errorf("Decrypt: AEAD failed: %w", err) } plaintextReader := bytes.NewReader(plaintext) sig, err := extractVariableBytes(plaintextReader, maxSignatureLen) if err != nil { - return nil, errors.Wrapf(err, "Decrypt: failed to read sig") + return nil, fmt.Errorf("Decrypt: failed to read sig: %w", err) } data, err := extractVariableBytes(plaintextReader, plaintextReader.Len()) if err != nil { - return nil, errors.Wrapf(err, "Decrypt: failed to extract user data") + return nil, fmt.Errorf("Decrypt: failed to extract user data: %w", err) } signatureData := make([]byte, 0, len(sig)+serializedPublicKeyLength) @@ -303,10 +304,10 @@ func (d *hdPrivKeyDecrypter) Decrypt(payload string) ([]byte, error) { hash := sha256.Sum256(signatureData) signatureKey, _, err := btcec.RecoverCompact(btcec.S256(), sig, hash[:]) if err != nil { - return nil, errors.Wrapf(err, "Decrypt: failed to verify signature") + return nil, fmt.Errorf("Decrypt: failed to verify signature: %w", err) } if verificationKey != nil && !signatureKey.IsEqual(verificationKey) { - return nil, errors.Errorf("Decrypt: signing key mismatch") + return nil, errors.New("Decrypt: signing key mismatch") } return data, nil @@ -331,7 +332,7 @@ func encryptWithPubKey(pubKey *btcec.PublicKey, plaintext []byte) (*btcec.Public ciphertext, err := aescbc.EncryptNoPadding(paddedSerializeBigInt(aescbc.KeySize, sharedSecret), iv, plaintext) if err != nil { - return nil, nil, errors.Wrapf(err, "encryptWithPubKey: encrypt failed") + return nil, nil, fmt.Errorf("encryptWithPubKey: encrypt failed: %w", err) } return pubEph, ciphertext, nil @@ -342,7 +343,7 @@ func encryptWithPubKey(pubKey *btcec.PublicKey, plaintext []byte) (*btcec.Public func generateSharedEncryptionSecret(pubKey *btcec.PublicKey) (*btcec.PublicKey, *big.Int, error) { privEph, err := btcec.NewPrivateKey(btcec.S256()) if err != nil { - return nil, nil, errors.Wrapf(err, "generateSharedEncryptionSecretForAES: failed to generate key") + return nil, nil, fmt.Errorf("generateSharedEncryptionSecretForAES: failed to generate key: %w", err) } sharedSecret, _ := pubKey.ScalarMult(pubKey.X, pubKey.Y, privEph.D.Bytes()) @@ -374,7 +375,7 @@ func decryptWithPrivKey(privKey *btcec.PrivateKey, rawPubEph []byte, ciphertext plaintext, err := aescbc.DecryptNoPadding(paddedSerializeBigInt(aescbc.KeySize, sharedSecret), iv, ciphertext) if err != nil { - return nil, errors.Wrapf(err, "decryptWithPrivKey: failed to decrypt") + return nil, fmt.Errorf("decryptWithPrivKey: failed to decrypt: %w", err) } return plaintext, nil @@ -385,7 +386,7 @@ func decryptWithPrivKey(privKey *btcec.PrivateKey, rawPubEph []byte, ciphertext func recoverSharedEncryptionSecret(privKey *btcec.PrivateKey, rawPubEph []byte) (*big.Int, error) { pubEph, err := btcec.ParsePubKey(rawPubEph, btcec.S256()) if err != nil { - return nil, errors.Wrapf(err, "recoverSharedEncryptionSecretForAES: failed to parse pub eph") + return nil, fmt.Errorf("recoverSharedEncryptionSecretForAES: failed to parse pub eph: %w", err) } sharedSecret, _ := pubEph.ScalarMult(pubEph.X, pubEph.Y, privKey.D.Bytes()) diff --git a/vendor/github.com/muun/libwallet/errors.go b/vendor/github.com/muun/libwallet/errors.go new file mode 100644 index 0000000..6b9c3e4 --- /dev/null +++ b/vendor/github.com/muun/libwallet/errors.go @@ -0,0 +1,22 @@ +package libwallet + +const ( + ErrUnknown = 1 + ErrInvalidURI = 2 + ErrNetwork = 3 + ErrInvalidPrivateKey = 4 + ErrInvalidDerivationPath = 5 + ErrInvalidInvoice = 6 +) + +func ErrorCode(err error) int64 { + type coder interface { + Code() int64 + } + switch e := err.(type) { + case coder: + return e.Code() + default: + return ErrUnknown + } +} diff --git a/vendor/github.com/muun/libwallet/errors/errors.go b/vendor/github.com/muun/libwallet/errors/errors.go new file mode 100644 index 0000000..c24b075 --- /dev/null +++ b/vendor/github.com/muun/libwallet/errors/errors.go @@ -0,0 +1,28 @@ +package errors + +import ( + "errors" + "fmt" +) + +type Error struct { + err error + code int64 +} + +func (e *Error) Error() string { + return e.err.Error() +} + +func (e *Error) Code() int64 { + return e.code +} + +func New(code int64, msg string) error { + return &Error{errors.New(msg), code} +} + +func Errorf(code int64, format string, a ...interface{}) error { + err := fmt.Errorf(format, a...) + return &Error{err, code} +} diff --git a/vendor/github.com/muun/libwallet/go.mod b/vendor/github.com/muun/libwallet/go.mod index 86099f4..5e9299f 100644 --- a/vendor/github.com/muun/libwallet/go.mod +++ b/vendor/github.com/muun/libwallet/go.mod @@ -10,10 +10,14 @@ require ( github.com/lightningnetwork/lightning-onion v1.0.1 github.com/lightningnetwork/lnd v0.10.4-beta github.com/miekg/dns v1.1.29 // indirect + github.com/pdfcpu/pdfcpu v0.3.8 github.com/pkg/errors v0.9.1 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 - golang.org/x/mobile v0.0.0-20200720140940-1a48f808d81f // indirect + golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect google.golang.org/protobuf v1.25.0 gopkg.in/gormigrate.v1 v1.6.0 ) + +// Fork that includes the -cache flag for quicker builds +replace golang.org/x/mobile => github.com/champo/mobile v0.0.0-20201226003606-ef8e5756cda7 diff --git a/vendor/github.com/muun/libwallet/go.sum b/vendor/github.com/muun/libwallet/go.sum index f48ec84..9eba078 100644 --- a/vendor/github.com/muun/libwallet/go.sum +++ b/vendor/github.com/muun/libwallet/go.sum @@ -24,7 +24,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= -github.com/btcsuite/btcd v0.20.0-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.20.1-beta.0.20200513120220-b470eee47728/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= @@ -38,7 +37,6 @@ github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2ut github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/btcutil/psbt v1.0.2 h1:gCVY3KxdoEVU7Q6TjusPO+GANIwVgr9yTLqM+a6CZr8= github.com/btcsuite/btcutil/psbt v1.0.2/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ= -github.com/btcsuite/btcwallet v0.10.0/go.mod h1:4TqBEuceheGNdeLNrelliLHJzmXauMM2vtWfuy1pFiM= github.com/btcsuite/btcwallet v0.11.1-0.20200612012534-48addcd5591a h1:AZ1Mf0gd9mgJqrTTIFUc17ep9EKUbQusVAIzJ6X+x3Q= github.com/btcsuite/btcwallet v0.11.1-0.20200612012534-48addcd5591a/go.mod h1:9+AH3V5mcTtNXTKe+fe63fDLKGOwQbZqmvOVUef+JFE= github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 h1:KGHMW5sd7yDdDMkCZ/JpP0KltolFsQcB973brBnfj4c= @@ -48,7 +46,6 @@ github.com/btcsuite/btcwallet/wallet/txrules v1.0.0/go.mod h1:UwQE78yCerZ313EXZw github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0 h1:6DxkcoMnCPY4E9cUDPB5tbuuf40SmmMkSQkoE8vCT+s= github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= github.com/btcsuite/btcwallet/walletdb v1.0.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk= -github.com/btcsuite/btcwallet/walletdb v1.1.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk= github.com/btcsuite/btcwallet/walletdb v1.2.0/go.mod h1:9cwc1Yyg4uvd4ZdfdoMnALji+V9gfWSMfxEdLdR5Vwc= github.com/btcsuite/btcwallet/walletdb v1.3.1/go.mod h1:9cwc1Yyg4uvd4ZdfdoMnALji+V9gfWSMfxEdLdR5Vwc= github.com/btcsuite/btcwallet/walletdb v1.3.2/go.mod h1:GZCMPNpUu5KE3ASoVd+k06p/1OW8OwNGCCaNWRto2cQ= @@ -57,7 +54,6 @@ github.com/btcsuite/btcwallet/walletdb v1.3.3/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPT github.com/btcsuite/btcwallet/wtxmgr v1.0.0/go.mod h1:vc4gBprll6BP0UJ+AIGDaySoc7MdAmZf8kelfNb8CFY= github.com/btcsuite/btcwallet/wtxmgr v1.2.0 h1:ZUYPsSv8GjF9KK7lboB2OVHF0uYEcHxgrCfFWqPd9NA= github.com/btcsuite/btcwallet/wtxmgr v1.2.0/go.mod h1:h8hkcKUE3X7lMPzTUoGnNiw5g7VhGrKEW3KpR2r0VnY= -github.com/btcsuite/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:QcFA8DZHtuIAdYKCq/BzELOaznRsCvwf4zTPmaYwaig= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc= @@ -72,6 +68,10 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/champo/mobile v0.0.0-20201225234154-3393de95d3bb h1:Doj1b3qkFX5zakU7uJ1lpsER6GNS4R65Zbfrpz2fIWE= +github.com/champo/mobile v0.0.0-20201225234154-3393de95d3bb/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= +github.com/champo/mobile v0.0.0-20201226003606-ef8e5756cda7 h1:jbaq2lXHNbmLj9Ab3upCbYSZ/j/TQ6yzDwie/pNyfqA= +github.com/champo/mobile v0.0.0-20201226003606-ef8e5756cda7/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -87,6 +87,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= @@ -132,9 +133,14 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v0.0.0-20170724004829-f2862b476edc/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.8.6 h1:XvND7+MPP7Jp+JpqSZ7naSl5nVZf6k0LbL1V3EKh0zc= github.com/grpc-ecosystem/grpc-gateway v1.8.6/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hhrutter/lzw v0.0.0-20190827003112-58b82c5a41cc/go.mod h1:yJBvOcu1wLQ9q9XZmfiPfur+3dQJuIhYQsMGLYcItZk= +github.com/hhrutter/lzw v0.0.0-20190829144645-6f07a24e8650 h1:1yY/RQWNSBjJe2GDCIYoLmpWVidrooriUr4QS/zaATQ= +github.com/hhrutter/lzw v0.0.0-20190829144645-6f07a24e8650/go.mod h1:yJBvOcu1wLQ9q9XZmfiPfur+3dQJuIhYQsMGLYcItZk= +github.com/hhrutter/tiff v0.0.0-20190829141212-736cae8d0bc7 h1:o1wMw7uTNyA58IlEdDpxIrtFHTgnvYzA8sCQz8luv94= +github.com/hhrutter/tiff v0.0.0-20190829141212-736cae8d0bc7/go.mod h1:WkUxfS2JUu3qPo6tRld7ISb8HiC0gVSU91kooBMDVok= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= @@ -145,8 +151,6 @@ github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= -github.com/jinzhu/gorm v1.9.15 h1:OdR1qFvtXktlxk73XFYMiYn9ywzTwytqe4QkuMRqc38= -github.com/jinzhu/gorm v1.9.15/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= @@ -174,25 +178,22 @@ github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec h1:n1NeQ3SgUHyISrjFF github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lightninglabs/gozmq v0.0.0-20190710231225-cea2a031735d/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= -github.com/lightninglabs/neutrino v0.10.0/go.mod h1:C3KhCMk1Mcx3j8v0qRVWM1Ow6rIJSvSPnUAq00ZNAfk= github.com/lightninglabs/neutrino v0.11.0/go.mod h1:CuhF0iuzg9Sp2HO6ZgXgayviFTn1QHdSTJlMncK80wg= github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200 h1:j4iZ1XlUAPQmW6oSzMcJGILYsRHNs+4O3Gk+2Ms5Dww= github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200/go.mod h1:MlZmoKa7CJP3eR1s5yB7Rm5aSyadpKkxqAwLQmog7N0= github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d/go.mod h1:KDb67YMzoh4eudnzClmvs2FbiLG9vxISmLApUkCa4uI= -github.com/lightningnetwork/lightning-onion v0.0.0-20190909101754-850081b08b6a/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4= github.com/lightningnetwork/lightning-onion v1.0.1 h1:qChGgS5+aPxFeR6JiUsGvanei1bn6WJpYbvosw/1604= github.com/lightningnetwork/lightning-onion v1.0.1/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4= -github.com/lightningnetwork/lnd v0.8.0-beta h1:HmmhSRTq48qobqQF8YLqNa8eKU8dDBNbWWpr2VzycJM= -github.com/lightningnetwork/lnd v0.8.0-beta/go.mod h1:nq06y2BDv7vwWeMmwgB7P3pT7/Uj7sGf5FzHISVD6t4= github.com/lightningnetwork/lnd v0.10.4-beta h1:Af2zOCPePeaU8Tkl8IqtTjr4BP3zYfi+hAtQYcCMM58= github.com/lightningnetwork/lnd v0.10.4-beta/go.mod h1:4d02pduRVtZwgTJ+EimKJTsEAY0jDwi0SPE9h5aRneM= github.com/lightningnetwork/lnd/cert v1.0.2 h1:g2rEu+sM2Uyz0bpfuvwri/ks6R/26H5iY1NcGbpDJ+c= @@ -217,13 +218,16 @@ github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8/go.mod h1:W1PPwlIAgtquWB github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg= github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/muun/libwallet v0.4.0 h1:mqvEA+EpZeyXPOhcm61H8OL3AQxEuvelsm3VqYqIEIY= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pdfcpu/pdfcpu v0.3.8 h1:wdKii186dzmr/aP/fkJl2s9yT3TZcwc1VqgfabNymGI= +github.com/pdfcpu/pdfcpu v0.3.8/go.mod h1:EfJ1EIo3n5+YlGF53DGe1yF1wQLiqK1eqGDN5LuKALs= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -269,23 +273,22 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190823064033-3a9bac650e44/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM= +golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20200720140940-1a48f808d81f h1:I/h48WbtIgA+7yh90BQGaTm4aoyybl/D5N+N6JIfuCI= -golang.org/x/mobile v0.0.0-20200720140940-1a48f808d81f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd h1:ePuNC7PZ6O5BzgPn9bZayERXBdfZjUYoXEf5BTfDfh8= golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -298,7 +301,6 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -309,7 +311,6 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -323,14 +324,11 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2IVY3KZs6p9mix0ziNYJM= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -352,19 +350,16 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= @@ -374,22 +369,20 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v1 v1.0.1 h1:oQFRXzZ7CkBGdm1XZm/EbQYaYNNEElNBOd09M6cqNso= gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gormigrate.v1 v1.6.0 h1:XpYM6RHQPmzwY7Uyu+t+xxMXc86JYFJn4nEc9HzQjsI= gopkg.in/gormigrate.v1 v1.6.0/go.mod h1:Lf00lQrHqfSYWiTtPcyQabsDdM6ejZaMgV0OU6JMSlw= -gopkg.in/macaroon-bakery.v2 v2.0.1 h1:0N1TlEdfLP4HXNCg7MQUMp5XwvOoxk+oe9Owr2cpvsc= gopkg.in/macaroon-bakery.v2 v2.0.1/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA= -gopkg.in/macaroon.v2 v2.0.0 h1:LVWycAfeJBUjCIqfR9gqlo7I8vmiXRr51YEOZ1suop8= gopkg.in/macaroon.v2 v2.0.0/go.mod h1:+I6LnTMkm/uV5ew/0nsulNjL16SK4+C8yDmRUzHR17I= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/vendor/github.com/muun/libwallet/hdprivatekey.go b/vendor/github.com/muun/libwallet/hdprivatekey.go index eed1f56..398c319 100644 --- a/vendor/github.com/muun/libwallet/hdprivatekey.go +++ b/vendor/github.com/muun/libwallet/hdprivatekey.go @@ -2,10 +2,11 @@ package libwallet import ( "crypto/sha256" + "errors" + "fmt" "strings" "github.com/muun/libwallet/hdpath" - "github.com/pkg/errors" "github.com/btcsuite/btcutil/hdkeychain" ) @@ -91,17 +92,17 @@ func (p *HDPrivateKey) DerivedAt(index int64, hardened bool) (*HDPrivateKey, err func (p *HDPrivateKey) DeriveTo(path string) (*HDPrivateKey, error) { if !strings.HasPrefix(path, p.Path) { - return nil, errors.Errorf("derivation path %v is not prefix of the keys path %v", path, p.Path) + return nil, fmt.Errorf("derivation path %v is not prefix of the keys path %v", path, p.Path) } firstPath, err := hdpath.Parse(p.Path) if err != nil { - return nil, errors.Wrapf(err, "couldn't parse derivation path %v", p.Path) + return nil, fmt.Errorf("couldn't parse derivation path %v: %w", p.Path, err) } secondPath, err := hdpath.Parse(path) if err != nil { - return nil, errors.Wrapf(err, "couldn't parse derivation path %v", path) + return nil, fmt.Errorf("couldn't parse derivation path %v: %w", path, err) } indexes := secondPath.IndexesFrom(firstPath) @@ -109,7 +110,7 @@ func (p *HDPrivateKey) DeriveTo(path string) (*HDPrivateKey, error) { for depth, index := range indexes { derivedKey, err = derivedKey.DerivedAt(int64(index.Index), index.Hardened) if err != nil { - return nil, errors.Wrapf(err, "failed to derive key at path %v on depth %v", path, depth) + return nil, fmt.Errorf("failed to derive key at path %v on depth %v: %w", path, depth, err) } } // The generated path has no names in it, so replace it diff --git a/vendor/github.com/muun/libwallet/hdpublickey.go b/vendor/github.com/muun/libwallet/hdpublickey.go index 83249fb..45203e4 100644 --- a/vendor/github.com/muun/libwallet/hdpublickey.go +++ b/vendor/github.com/muun/libwallet/hdpublickey.go @@ -1,11 +1,13 @@ package libwallet import ( + "errors" + "fmt" "strings" "github.com/muun/libwallet/hdpath" - "github.com/pkg/errors" + "github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/hdkeychain" ) @@ -42,7 +44,7 @@ func (p *HDPublicKey) String() string { func (p *HDPublicKey) DerivedAt(index int64) (*HDPublicKey, error) { if index&hdkeychain.HardenedKeyStart != 0 { - return nil, errors.Errorf("can't derive a hardened pub key (index %v)", index) + return nil, fmt.Errorf("can't derive a hardened pub key (index %v)", index) } child, err := p.key.Child(uint32(index)) @@ -57,29 +59,29 @@ func (p *HDPublicKey) DerivedAt(index int64) (*HDPublicKey, error) { func (p *HDPublicKey) DeriveTo(path string) (*HDPublicKey, error) { if !strings.HasPrefix(path, p.Path) { - return nil, errors.Errorf("derivation path %v is not prefix of the keys path %v", path, p.Path) + return nil, fmt.Errorf("derivation path %v is not prefix of the keys path %v", path, p.Path) } firstPath, err := hdpath.Parse(p.Path) if err != nil { - return nil, errors.Wrapf(err, "couldn't parse derivation path %v", p.Path) + return nil, fmt.Errorf("couldn't parse derivation path %v: %w", p.Path, err) } secondPath, err := hdpath.Parse(path) if err != nil { - return nil, errors.Wrapf(err, "couldn't parse derivation path %v", path) + return nil, fmt.Errorf("couldn't parse derivation path %v: %w", path, err) } indexes := secondPath.IndexesFrom(firstPath) derivedKey := p for depth, index := range indexes { if index.Hardened { - return nil, errors.Errorf("can't derive a hardened pub key (path %v)", path) + return nil, fmt.Errorf("can't derive a hardened pub key (path %v)", path) } derivedKey, err = derivedKey.DerivedAt(int64(index.Index)) if err != nil { - return nil, errors.Wrapf(err, "failed to derive key at path %v on depth %v", path, depth) + return nil, fmt.Errorf("failed to derive key at path %v on depth %v: %w", path, depth, err) } } // The generated path has no names in it, so replace it @@ -98,3 +100,17 @@ func (p *HDPublicKey) Raw() []byte { return key.SerializeCompressed() } + +// Fingerprint returns the 4-byte fingerprint for this pubkey +func (p *HDPublicKey) Fingerprint() []byte { + + key, err := p.key.ECPubKey() + if err != nil { + panic("failed to extract pub key") + } + + bytes := key.SerializeCompressed() + hash := btcutil.Hash160(bytes) + + return hash[:4] +} diff --git a/vendor/github.com/muun/libwallet/incoming_swap.go b/vendor/github.com/muun/libwallet/incoming_swap.go index 0b354e1..69c7fe8 100644 --- a/vendor/github.com/muun/libwallet/incoming_swap.go +++ b/vendor/github.com/muun/libwallet/incoming_swap.go @@ -3,6 +3,7 @@ package libwallet import ( "bytes" "crypto/sha256" + "errors" "fmt" "github.com/btcsuite/btcd/chaincfg" @@ -12,7 +13,6 @@ import ( "github.com/lightningnetwork/lnd/lnwire" "github.com/muun/libwallet/hdpath" "github.com/muun/libwallet/sphinx" - "github.com/pkg/errors" ) type coinIncomingSwap struct { @@ -24,6 +24,7 @@ type coinIncomingSwap struct { SwapServerPublicKey []byte ExpirationHeight int64 VerifyOutputAmount bool // used only for fulfilling swaps through IncomingSwap + Collect btcutil.Amount } func (c *coinIncomingSwap) SignInput(index int, tx *wire.MsgTx, userKey *HDPrivateKey, muunKey *HDPublicKey) error { @@ -124,13 +125,16 @@ func (c *coinIncomingSwap) SignInput(index int, tx *wire.MsgTx, userKey *HDPriva // Now check the information we have against the sphinx created by the payer if len(c.Sphinx) > 0 { + // This incoming swap might be collecting debt, which would be deducted from the outputAmount + // so we add it back up so the amount will match with the sphinx + expectedAmount := outputAmount + lnwire.NewMSatFromSatoshis(c.Collect) err = sphinx.Validate( c.Sphinx, c.PaymentHash256, secrets.PaymentSecret, nodeKey, uint32(c.ExpirationHeight), - outputAmount, + expectedAmount, c.Network, ) if err != nil { @@ -175,7 +179,7 @@ func (c *coinIncomingSwap) FullySignInput(index int, tx *wire.MsgTx, userKey, mu derivedMuunKey, err := muunKey.DeriveTo(secrets.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive muun key") + return fmt.Errorf("failed to derive muun key: %w", err) } muunSignature, err := c.signature(index, tx, userKey.PublicKey(), derivedMuunKey.PublicKey(), derivedMuunKey) diff --git a/vendor/github.com/muun/libwallet/invoice.go b/vendor/github.com/muun/libwallet/invoice.go index b983fda..983800a 100644 --- a/vendor/github.com/muun/libwallet/invoice.go +++ b/vendor/github.com/muun/libwallet/invoice.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/lightningnetwork/lnd/zpay32" - "github.com/pkg/errors" + "github.com/muun/libwallet/errors" ) // Invoice is muun's invoice struct @@ -27,11 +27,11 @@ func ParseInvoice(rawInput string, network *Network) (*Invoice, error) { _, components := buildUriFromString(rawInput, lightningScheme) if components == nil { - return nil, errors.Errorf("failed to parse uri %v", rawInput) + return nil, errors.Errorf(ErrInvalidInvoice, "failed to parse uri %v", rawInput) } if components.Scheme != "lightning" { - return nil, errors.Errorf("invalid scheme %v", components.Scheme) + return nil, errors.Errorf(ErrInvalidInvoice, "invalid scheme %v", components.Scheme) } invoice := components.Opaque @@ -44,7 +44,7 @@ func ParseInvoice(rawInput string, network *Network) (*Invoice, error) { parsedInvoice, err := zpay32.Decode(invoice, network.network) if err != nil { - return nil, errors.Wrapf(err, "Couldnt parse invoice") + return nil, errors.Errorf(ErrInvalidInvoice, "Couldn't parse invoice: %w", err) } var fallbackAdd *MuunPaymentURI @@ -52,7 +52,7 @@ func ParseInvoice(rawInput string, network *Network) (*Invoice, error) { if parsedInvoice.FallbackAddr != nil { fallbackAdd, err = GetPaymentURI(parsedInvoice.FallbackAddr.String(), network) if err != nil { - return nil, errors.Wrapf(err, "Couldnt get address") + return nil, errors.Errorf(ErrInvalidInvoice, "Couldn't get address: %w", err) } } diff --git a/vendor/github.com/muun/libwallet/invoices.go b/vendor/github.com/muun/libwallet/invoices.go index 91e50db..2a4819f 100644 --- a/vendor/github.com/muun/libwallet/invoices.go +++ b/vendor/github.com/muun/libwallet/invoices.go @@ -5,6 +5,7 @@ import ( "crypto/sha256" "encoding/binary" "encoding/hex" + "errors" "fmt" "path" "time" @@ -16,9 +17,9 @@ import ( "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/zpay32" - "github.com/pkg/errors" "github.com/muun/libwallet/hdpath" + "github.com/muun/libwallet/sphinx" "github.com/muun/libwallet/walletdb" ) @@ -185,6 +186,9 @@ func CreateInvoice(net *Network, userKey *HDPrivateKey, routeHints *RouteHints, if err != nil { return "", err } + if dbInvoice == nil { + return "", nil + } var paymentHash [32]byte copy(paymentHash[:], dbInvoice.PaymentHash) @@ -268,6 +272,76 @@ func CreateInvoice(net *Network, userKey *HDPrivateKey, routeHints *RouteHints, return bech32, nil } +// ExposePreimage gives the preimage matching a payment hash if we have it +func ExposePreimage(paymentHash []byte) ([]byte, error) { + + if len(paymentHash) != 32 { + return nil, fmt.Errorf("ExposePreimage: received invalid hash len %v", len(paymentHash)) + } + + // Lookup invoice data matching this HTLC using the payment hash + db, err := openDB() + if err != nil { + return nil, err + } + defer db.Close() + + secrets, err := db.FindByPaymentHash(paymentHash) + if err != nil { + return nil, fmt.Errorf("could not find invoice data for payment hash: %w", err) + } + + return secrets.Preimage, nil +} + +func IsInvoiceFulfillable(paymentHash, onionBlob []byte, amount int64, userKey *HDPrivateKey, net *Network) error { + if len(paymentHash) != 32 { + return fmt.Errorf("IsInvoiceFulfillable: received invalid hash len %v", len(paymentHash)) + } + + // Lookup invoice data matching this HTLC using the payment hash + db, err := openDB() + if err != nil { + return err + } + defer db.Close() + + secrets, err := db.FindByPaymentHash(paymentHash) + if err != nil { + return fmt.Errorf("IsInvoiceFulfillable: could not find invoice data for payment hash: %w", err) + } + + if len(onionBlob) == 0 { + return nil + } + + identityKeyPath := hdpath.MustParse(secrets.KeyPath).Child(identityKeyChildIndex) + + nodeHDKey, err := userKey.DeriveTo(identityKeyPath.String()) + if err != nil { + return fmt.Errorf("IsInvoiceFulfillable: failed to derive key: %w", err) + } + nodeKey, err := nodeHDKey.key.ECPrivKey() + if err != nil { + return fmt.Errorf("IsInvoiceFulfillable: failed to get priv key: %w", err) + } + + err = sphinx.Validate( + onionBlob, + paymentHash, + secrets.PaymentSecret, + nodeKey, + 0, // This is used internally by the sphinx decoder but it's not needed + lnwire.MilliSatoshi(uint64(amount)*1000), + net.network, + ) + if err != nil { + return fmt.Errorf("IsInvoiceFuflillable: invalid sphinx: %w", err) + } + + return nil +} + type IncomingSwap struct { FulfillmentTx []byte MuunSignature []byte @@ -282,6 +356,7 @@ type IncomingSwap struct { HtlcExpiration int64 HtlcBlock []byte // unused ConfirmationTarget int64 // to validate fee rate, unused for now + CollectInSats int64 } func (s *IncomingSwap) VerifyAndFulfill(userKey *HDPrivateKey, muunKey *HDPublicKey, net *Network) ([]byte, error) { @@ -313,6 +388,7 @@ func (s *IncomingSwap) VerifyAndFulfill(userKey *HDPrivateKey, muunKey *HDPublic SwapServerPublicKey: swapServerPublicKey, ExpirationHeight: s.HtlcExpiration, VerifyOutputAmount: true, + Collect: btcutil.Amount(s.CollectInSats), } err = coin.SignInput(0, &tx, userKey, muunKey) if err != nil { diff --git a/vendor/github.com/muun/libwallet/partiallysignedtransaction.go b/vendor/github.com/muun/libwallet/partiallysignedtransaction.go index 7cf0451..002feb4 100644 --- a/vendor/github.com/muun/libwallet/partiallysignedtransaction.go +++ b/vendor/github.com/muun/libwallet/partiallysignedtransaction.go @@ -3,6 +3,8 @@ package libwallet import ( "bytes" "encoding/hex" + "errors" + "fmt" "github.com/muun/libwallet/addresses" @@ -11,7 +13,6 @@ import ( "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" - "github.com/pkg/errors" ) type SigningExpectations struct { @@ -64,6 +65,7 @@ type InputIncomingSwap interface { PaymentHash256() []byte SwapServerPublicKey() string ExpirationHeight() int64 + CollectInSats() int64 } type Input interface { @@ -105,7 +107,7 @@ func NewPartiallySignedTransaction(inputs *InputList, rawTx []byte) (*PartiallyS tx := wire.NewMsgTx(0) err := tx.Deserialize(bytes.NewReader(rawTx)) if err != nil { - return nil, errors.Wrapf(err, "failed to decode tx") + return nil, fmt.Errorf("failed to decode tx: %w", err) } return &PartiallySignedTransaction{tx: tx, inputs: inputs.Inputs()}, nil @@ -127,13 +129,13 @@ func (p *PartiallySignedTransaction) Sign(userKey *HDPrivateKey, muunKey *HDPubl coins, err := p.coins(userKey.Network) if err != nil { - return nil, errors.Wrapf(err, "could not convert input data to coin") + return nil, fmt.Errorf("could not convert input data to coin: %w", err) } for i, coin := range coins { err = coin.SignInput(i, p.tx, userKey, muunKey) if err != nil { - return nil, errors.Wrapf(err, "failed to sign input") + return nil, fmt.Errorf("failed to sign input: %w", err) } } @@ -145,13 +147,13 @@ func (p *PartiallySignedTransaction) FullySign(userKey, muunKey *HDPrivateKey) ( coins, err := p.coins(userKey.Network) if err != nil { - return nil, errors.Wrapf(err, "could not convert input data to coin") + return nil, fmt.Errorf("could not convert input data to coin: %w", err) } for i, coin := range coins { err = coin.FullySignInput(i, p.tx, userKey, muunKey) if err != nil { - return nil, errors.Wrapf(err, "failed to sign input") + return nil, fmt.Errorf("failed to sign input: %w", err) } } @@ -168,11 +170,11 @@ func (p *PartiallySignedTransaction) Verify(expectations *SigningExpectations, u // If we were to receive more than that, we consider it invalid. if expectations.change != nil { if len(p.tx.TxOut) != 2 { - return errors.Errorf("expected destination and change outputs but found %v", len(p.tx.TxOut)) + return fmt.Errorf("expected destination and change outputs but found %v", len(p.tx.TxOut)) } } else { if len(p.tx.TxOut) != 1 { - return errors.Errorf("expected destination output only but found %v", len(p.tx.TxOut)) + return fmt.Errorf("expected destination output only but found %v", len(p.tx.TxOut)) } } @@ -207,12 +209,12 @@ func (p *PartiallySignedTransaction) Verify(expectations *SigningExpectations, u // Fail if not destination output was found in the TX. if toOutput == nil { - return errors.Errorf("destination output is not present") + return errors.New("destination output is not present") } // Verify destination output value matches expected amount if toOutput.Value != expectedAmount { - return errors.Errorf("destination amount is mismatched. found %v expected %v", toOutput.Value, expectedAmount) + return fmt.Errorf("destination amount is mismatched. found %v expected %v", toOutput.Value, expectedAmount) } /* @@ -237,25 +239,25 @@ func (p *PartiallySignedTransaction) Verify(expectations *SigningExpectations, u // Verify change output is spendable by the wallet. if expectedChange != nil { if changeOutput == nil { - return errors.Errorf("Change is not present") + return errors.New("change is not present") } expectedChangeAmount := actualTotal - expectedAmount - expectedFee if changeOutput.Value != expectedChangeAmount { - return errors.Errorf("Change amount is mismatched. found %v expected %v", + return fmt.Errorf("change amount is mismatched. found %v expected %v", changeOutput.Value, expectedChangeAmount) } derivedUserKey, err := userPublicKey.DeriveTo(expectedChange.DerivationPath()) if err != nil { - return errors.Wrapf(err, "failed to derive user key to change path %v", - expectedChange.DerivationPath()) + return fmt.Errorf("failed to derive user key to change path %v: %w", + expectedChange.DerivationPath(), err) } derivedMuunKey, err := muunPublickKey.DeriveTo(expectedChange.DerivationPath()) if err != nil { - return errors.Wrapf(err, "failed to derive muun key to change path %v", - expectedChange.DerivationPath()) + return fmt.Errorf("failed to derive muun key to change path %v: %w", + expectedChange.DerivationPath(), err) } expectedChangeAddress, err := addresses.Create( @@ -266,24 +268,24 @@ func (p *PartiallySignedTransaction) Verify(expectations *SigningExpectations, u network.network, ) if err != nil { - return errors.Wrapf(err, "failed to build the change address with version %v", - expectedChange.Version()) + return fmt.Errorf("failed to build the change address with version %v: %w", + expectedChange.Version(), err) } if expectedChangeAddress.Address() != expectedChange.Address() { - return errors.Errorf("mismatched change address. found %v, expected %v", + return fmt.Errorf("mismatched change address. found %v, expected %v", expectedChange.Address(), expectedChangeAddress.Address()) } actualFee := actualTotal - expectedAmount - expectedChangeAmount if actualFee != expectedFee { - return errors.Errorf("fee mismatched. found %v, expected %v", actualFee, expectedFee) + return fmt.Errorf("fee mismatched. found %v, expected %v", actualFee, expectedFee) } } else { actualFee := actualTotal - expectedAmount if actualFee >= expectedFee+dustThreshold { - return errors.Errorf("change output is too big to be burned as fee") + return errors.New("change output is too big to be burned as fee") } } @@ -300,11 +302,11 @@ func (p *PartiallySignedTransaction) Verify(expectations *SigningExpectations, u func addressToScript(address string, network *Network) ([]byte, error) { parsedAddress, err := btcutil.DecodeAddress(address, network.network) if err != nil { - return nil, errors.Wrapf(err, "failed to parse address %v", address) + return nil, fmt.Errorf("failed to parse address %v: %w", address, err) } script, err := txscript.PayToAddrScript(parsedAddress) if err != nil { - return nil, errors.Wrapf(err, "failed to generate script for address %v", address) + return nil, fmt.Errorf("failed to generate script for address %v: %w", address, err) } return script, nil } @@ -313,7 +315,7 @@ func newTransaction(tx *wire.MsgTx) (*Transaction, error) { var buf bytes.Buffer err := tx.Serialize(&buf) if err != nil { - return nil, errors.Wrapf(err, "failed to encode tx") + return nil, fmt.Errorf("failed to encode tx: %w", err) } return &Transaction{ @@ -422,8 +424,9 @@ func createCoin(input Input, network *Network) (coin, error) { PaymentHash256: swap.PaymentHash256(), SwapServerPublicKey: swapServerPublicKey, ExpirationHeight: swap.ExpirationHeight(), + Collect: btcutil.Amount(swap.CollectInSats()), }, nil default: - return nil, errors.Errorf("can't create coin from input version %v", version) + return nil, fmt.Errorf("can't create coin from input version %v", version) } } diff --git a/vendor/github.com/muun/libwallet/publickey.go b/vendor/github.com/muun/libwallet/publickey.go index 33451ad..f9c4812 100644 --- a/vendor/github.com/muun/libwallet/publickey.go +++ b/vendor/github.com/muun/libwallet/publickey.go @@ -1,8 +1,9 @@ package libwallet import ( + "fmt" + "github.com/btcsuite/btcd/btcec" - "github.com/pkg/errors" ) type PublicKey struct { @@ -12,7 +13,7 @@ type PublicKey struct { func NewPublicKeyFromBytes(bytes []byte) (*PublicKey, error) { key, err := btcec.ParsePubKey(bytes, btcec.S256()) if err != nil { - return nil, errors.Wrapf(err, "NewPublicKeyFromBytes: failed to parse pub key") + return nil, fmt.Errorf("NewPublicKeyFromBytes: failed to parse pub key: %w", err) } return &PublicKey{key}, nil diff --git a/vendor/github.com/muun/libwallet/recoverycode/recoverycode.go b/vendor/github.com/muun/libwallet/recoverycode/recoverycode.go index 58289ac..c5f52f9 100644 --- a/vendor/github.com/muun/libwallet/recoverycode/recoverycode.go +++ b/vendor/github.com/muun/libwallet/recoverycode/recoverycode.go @@ -4,6 +4,7 @@ import ( "crypto/hmac" "crypto/rand" "crypto/sha256" + "encoding/hex" "errors" fmt "fmt" "strings" @@ -89,9 +90,14 @@ func ConvertToKey(code, salt string) (*btcec.PrivateKey, error) { switch version { case 1: + saltBytes, err := hex.DecodeString(salt) + if err != nil { + return nil, fmt.Errorf("failed to decode salt: %w", err) + } + input, err = scrypt.Key( []byte(code), - []byte(salt), + saltBytes, kdfIterations, kdfBlockSize, kdfParallelizationFactor, diff --git a/vendor/github.com/muun/libwallet/segwit.go b/vendor/github.com/muun/libwallet/segwit.go index b2d6144..6615248 100644 --- a/vendor/github.com/muun/libwallet/segwit.go +++ b/vendor/github.com/muun/libwallet/segwit.go @@ -2,24 +2,24 @@ package libwallet import ( "crypto/sha256" + "fmt" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" - "github.com/pkg/errors" ) func signNativeSegwitInput(index int, tx *wire.MsgTx, privateKey *HDPrivateKey, witnessScript []byte, amount btcutil.Amount) ([]byte, error) { privKey, err := privateKey.key.ECPrivKey() if err != nil { - return nil, errors.Wrapf(err, "failed to produce EC priv key for signing") + return nil, fmt.Errorf("failed to produce EC priv key for signing: %w", err) } sigHashes := txscript.NewTxSigHashes(tx) sig, err := txscript.RawTxInWitnessSignature(tx, sigHashes, index, int64(amount), witnessScript, txscript.SigHashAll, privKey) if err != nil { - return nil, errors.Wrapf(err, "failed to sign V4 input") + return nil, fmt.Errorf("failed to sign V4 input: %w", err) } return sig, nil @@ -44,20 +44,20 @@ func signNonNativeSegwitInput(index int, tx *wire.MsgTx, privateKey *HDPrivateKe builder.AddData(redeemScript) script, err := builder.Script() if err != nil { - return nil, errors.Wrapf(err, "failed to generate signing script") + return nil, fmt.Errorf("failed to generate signing script: %w", err) } txInput.SignatureScript = script privKey, err := privateKey.key.ECPrivKey() if err != nil { - return nil, errors.Wrapf(err, "failed to produce EC priv key for signing") + return nil, fmt.Errorf("failed to produce EC priv key for signing: %w", err) } sigHashes := txscript.NewTxSigHashes(tx) sig, err := txscript.RawTxInWitnessSignature( tx, sigHashes, index, int64(amount), witnessScript, txscript.SigHashAll, privKey) if err != nil { - return nil, errors.Wrapf(err, "failed to sign V3 input") + return nil, fmt.Errorf("failed to sign V3 input: %w", err) } return sig, nil diff --git a/vendor/github.com/muun/libwallet/sphinx/sphinx.go b/vendor/github.com/muun/libwallet/sphinx/sphinx.go index f199471..8176dfe 100644 --- a/vendor/github.com/muun/libwallet/sphinx/sphinx.go +++ b/vendor/github.com/muun/libwallet/sphinx/sphinx.go @@ -44,15 +44,22 @@ func Validate( // Validate payment secret if it exists if payload.MPP != nil { paymentAddr := payload.MPP.PaymentAddr() + amountToForward := payload.ForwardingInfo().AmountToForward + total := payload.MultiPath().TotalMsat() if !bytes.Equal(paymentAddr[:], paymentSecret) { return errors.New("sphinx payment secret does not match") } - if amount != 0 && payload.ForwardingInfo().AmountToForward > amount { + + if amount != 0 && amountToForward > amount { return fmt.Errorf( - "sphinx payment amount does not match (%v != %v)", amount, payload.ForwardingInfo().AmountToForward, + "sphinx payment amount does not match (%v != %v)", amount, amountToForward, ) } + + if amountToForward < total { + return fmt.Errorf("payment is multipart. forwarded amt = %v, total amt = %v", amountToForward, total) + } } return nil } diff --git a/vendor/github.com/muun/libwallet/submarineSwapV1.go b/vendor/github.com/muun/libwallet/submarineSwapV1.go index 68b7586..3650e32 100644 --- a/vendor/github.com/muun/libwallet/submarineSwapV1.go +++ b/vendor/github.com/muun/libwallet/submarineSwapV1.go @@ -1,11 +1,13 @@ package libwallet import ( + "errors" + "fmt" + "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/muun/libwallet/swaps" - "github.com/pkg/errors" ) type coinSubmarineSwapV1 struct { @@ -24,7 +26,7 @@ func (c *coinSubmarineSwapV1) SignInput(index int, tx *wire.MsgTx, userKey *HDPr userKey, err := userKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive user key") + return fmt.Errorf("failed to derive user key: %w", err) } witnessScript, err := swaps.CreateWitnessScriptSubmarineSwapV1( @@ -40,7 +42,7 @@ func (c *coinSubmarineSwapV1) SignInput(index int, tx *wire.MsgTx, userKey *HDPr redeemScript, err := createNonNativeSegwitRedeemScript(witnessScript) if err != nil { - return errors.Wrapf(err, "failed to build reedem script for signing") + return fmt.Errorf("failed to build reedem script for signing: %w", err) } sig, err := signNonNativeSegwitInput( diff --git a/vendor/github.com/muun/libwallet/submarineSwapV2.go b/vendor/github.com/muun/libwallet/submarineSwapV2.go index c582a71..47fc8d3 100644 --- a/vendor/github.com/muun/libwallet/submarineSwapV2.go +++ b/vendor/github.com/muun/libwallet/submarineSwapV2.go @@ -1,11 +1,13 @@ package libwallet import ( + "errors" + "fmt" + "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/muun/libwallet/swaps" - "github.com/pkg/errors" ) type coinSubmarineSwapV2 struct { @@ -26,11 +28,11 @@ func (c *coinSubmarineSwapV2) SignInput(index int, tx *wire.MsgTx, userKey *HDPr userKey, err := userKey.DeriveTo(c.KeyPath) if err != nil { - return errors.Wrapf(err, "failed to derive user key") + return fmt.Errorf("failed to derive user key: %w", err) } if len(c.ServerSignature) == 0 { - return errors.Errorf("Swap server must provide signature") + return errors.New("swap server must provide signature") } witnessScript, err := swaps.CreateWitnessScriptSubmarineSwapV2( diff --git a/vendor/github.com/muun/libwallet/swaps/v2.go b/vendor/github.com/muun/libwallet/swaps/v2.go index 9c2b673..4c09860 100644 --- a/vendor/github.com/muun/libwallet/swaps/v2.go +++ b/vendor/github.com/muun/libwallet/swaps/v2.go @@ -11,7 +11,6 @@ import ( "github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/hdkeychain" "github.com/lightningnetwork/lnd/zpay32" - "github.com/pkg/errors" ) func (swap *SubmarineSwap) validateV2(rawInvoice string, userPublicKey, muunPublicKey *KeyDescriptor, originalExpirationInBlocks int64, network *chaincfg.Params) error { @@ -98,7 +97,7 @@ func (swap *SubmarineSwap) validateV2(rawInvoice string, userPublicKey, muunPubl if len(swap.PreimageInHex) > 0 { preimage, err := hex.DecodeString(swap.PreimageInHex) if err != nil { - return errors.Wrapf(err, "preimagehex is not actually hex 🤔") + return fmt.Errorf("preimageInHex is not valid hex: %w", err) } calculatedPaymentHash := sha256.Sum256(preimage) diff --git a/vendor/github.com/muun/libwallet/walletdb/walletdb.go b/vendor/github.com/muun/libwallet/walletdb/walletdb.go index c3742a1..ec91c88 100644 --- a/vendor/github.com/muun/libwallet/walletdb/walletdb.go +++ b/vendor/github.com/muun/libwallet/walletdb/walletdb.go @@ -1,6 +1,7 @@ package walletdb import ( + "errors" "log" "time" @@ -45,7 +46,10 @@ func Open(path string) (*DB, error) { } func migrate(db *gorm.DB) error { - m := gormigrate.New(db, gormigrate.DefaultOptions, []*gormigrate.Migration{ + opts := gormigrate.Options{ + UseTransaction: true, + } + m := gormigrate.New(db, &opts, []*gormigrate.Migration{ { ID: "initial", Migrate: func(tx *gorm.DB) error { @@ -59,7 +63,14 @@ func migrate(db *gorm.DB) error { State string UsedAt *time.Time } - return tx.CreateTable(&Invoice{}).Error + // This guard exists because at some point migrations were run outside a + // transactional context and a user experimented problems with an invoices + // table that was already created but whose migration had not been properly + // recorded. + if !tx.HasTable(&Invoice{}) { + return tx.CreateTable(&Invoice{}).Error + } + return nil }, Rollback: func(tx *gorm.DB) error { return tx.DropTable("invoices").Error @@ -90,6 +101,11 @@ func (d *DB) SaveInvoice(invoice *Invoice) error { func (d *DB) FindFirstUnusedInvoice() (*Invoice, error) { var invoice Invoice if res := d.db.Where(&Invoice{State: InvoiceStateRegistered}).First(&invoice); res.Error != nil { + + if errors.Is(res.Error, gorm.ErrRecordNotFound) { + return nil, nil + } + return nil, res.Error } invoice.ShortChanId = invoice.ShortChanId | (1 << 63) diff --git a/vendor/github.com/pdfcpu/pdfcpu/LICENSE.txt b/vendor/github.com/pdfcpu/pdfcpu/LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/pdfcpu/pdfcpu/internal/config/config.go b/vendor/github.com/pdfcpu/pdfcpu/internal/config/config.go new file mode 100644 index 0000000..fb833fd --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/internal/config/config.go @@ -0,0 +1,7 @@ +// generated by "go run gen.go". DO NOT EDIT. + +package config + +// ConfigFileBytes is a byteslice representing config.yml. +var ConfigFileBytes = []byte{ + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 10, 35, 32, 68, 101, 102, 97, 117, 108, 116, 32, 99, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 32, 35, 10, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 10, 10, 114, 101, 97, 100, 101, 114, 49, 53, 58, 32, 116, 114, 117, 101, 10, 100, 101, 99, 111, 100, 101, 65, 108, 108, 83, 116, 114, 101, 97, 109, 115, 58, 32, 102, 97, 108, 115, 101, 10, 10, 35, 32, 118, 97, 108, 105, 100, 97, 116, 105, 111, 110, 77, 111, 100, 101, 58, 32, 10, 35, 32, 86, 97, 108, 105, 100, 97, 116, 105, 111, 110, 83, 116, 114, 105, 99, 116, 44, 10, 35, 32, 86, 97, 108, 105, 100, 97, 116, 105, 111, 110, 82, 101, 108, 97, 120, 101, 100, 44, 10, 35, 32, 86, 97, 108, 105, 100, 97, 116, 105, 111, 110, 78, 111, 110, 101, 10, 118, 97, 108, 105, 100, 97, 116, 105, 111, 110, 77, 111, 100, 101, 58, 32, 86, 97, 108, 105, 100, 97, 116, 105, 111, 110, 82, 101, 108, 97, 120, 101, 100, 10, 10, 35, 32, 101, 111, 108, 32, 102, 111, 114, 32, 119, 114, 105, 116, 105, 110, 103, 58, 10, 35, 32, 69, 111, 108, 76, 70, 10, 35, 32, 69, 111, 108, 67, 82, 10, 35, 32, 69, 111, 108, 67, 82, 76, 70, 10, 101, 111, 108, 58, 32, 69, 111, 108, 76, 70, 10, 10, 119, 114, 105, 116, 101, 79, 98, 106, 101, 99, 116, 83, 116, 114, 101, 97, 109, 58, 32, 116, 114, 117, 101, 10, 119, 114, 105, 116, 101, 88, 82, 101, 102, 83, 116, 114, 101, 97, 109, 58, 32, 116, 114, 117, 101, 10, 101, 110, 99, 114, 121, 112, 116, 85, 115, 105, 110, 103, 65, 69, 83, 58, 32, 116, 114, 117, 101, 10, 10, 35, 32, 101, 110, 99, 114, 121, 112, 116, 75, 101, 121, 76, 101, 110, 103, 116, 104, 58, 32, 109, 97, 120, 32, 50, 53, 54, 32, 10, 101, 110, 99, 114, 121, 112, 116, 75, 101, 121, 76, 101, 110, 103, 116, 104, 58, 32, 50, 53, 54, 10, 10, 35, 32, 112, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 32, 102, 111, 114, 32, 101, 110, 99, 114, 121, 112, 116, 101, 100, 32, 102, 105, 108, 101, 115, 58, 32, 10, 35, 32, 45, 51, 57, 48, 49, 32, 61, 32, 48, 120, 70, 48, 67, 51, 32, 40, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 78, 111, 110, 101, 41, 10, 35, 32, 32, 32, 32, 45, 49, 32, 61, 32, 48, 120, 70, 70, 70, 70, 32, 40, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 65, 108, 108, 41, 10, 112, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 58, 32, 45, 51, 57, 48, 49, 10, 10, 35, 32, 100, 105, 115, 112, 108, 97, 121, 85, 110, 105, 116, 58, 10, 35, 32, 112, 111, 105, 110, 116, 115, 10, 35, 32, 105, 110, 99, 104, 101, 115, 10, 35, 32, 99, 109, 10, 35, 32, 109, 109, 10, 117, 110, 105, 116, 58, 32, 112, 111, 105, 110, 116, 115} diff --git a/vendor/github.com/pdfcpu/pdfcpu/internal/config/config.yml b/vendor/github.com/pdfcpu/pdfcpu/internal/config/config.yml new file mode 100644 index 0000000..cae6cde --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/internal/config/config.yml @@ -0,0 +1,37 @@ +######################### +# Default configuration # +######################### + +reader15: true +decodeAllStreams: false + +# validationMode: +# ValidationStrict, +# ValidationRelaxed, +# ValidationNone +validationMode: ValidationRelaxed + +# eol for writing: +# EolLF +# EolCR +# EolCRLF +eol: EolLF + +writeObjectStream: true +writeXRefStream: true +encryptUsingAES: true + +# encryptKeyLength: max 256 +encryptKeyLength: 256 + +# permissions for encrypted files: +# -3901 = 0xF0C3 (PermissionsNone) +# -1 = 0xFFFF (PermissionsAll) +permissions: -3901 + +# displayUnit: +# points +# inches +# cm +# mm +unit: points \ No newline at end of file diff --git a/vendor/github.com/pdfcpu/pdfcpu/internal/corefont/metrics/metrics.go b/vendor/github.com/pdfcpu/pdfcpu/internal/corefont/metrics/metrics.go new file mode 100644 index 0000000..19102b5 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/internal/corefont/metrics/metrics.go @@ -0,0 +1,55 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package metrics provides font metrics for the PDF standard fonts. +package metrics + +// The PostScript names of the 14 Type 1 fonts, aka the PDF core font set, are as follows: +// +// Times-Roman, +// Helvetica, +// Courier, +// Symbol, +// Times-Bold, +// Helvetica-Bold, +// Courier-Bold, +// ZapfDingbats, +// Times-Italic, +// Helvetica- Oblique, +// Courier-Oblique, +// Times-BoldItalic, +// Helvetica-BoldOblique, +// Courier-BoldOblique + +// CoreFontCharWidth returns the character width for fontName and c in glyph space units. +func CoreFontCharWidth(fontName string, c int) int { + var m map[int]string + switch fontName { + case "Symbol": + m = SymbolGlyphMap + case "ZapfDingbats": + m = ZapfDingbatsGlyphMap + default: + m = WinAnsiGlyphMap + } + glyphName := m[c] + fm := CoreFontMetrics[fontName] + w, ok := fm.W[glyphName] + if !ok { + w = 1000 //m.W["bullet"] + } + return w +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/internal/corefont/metrics/standard.go b/vendor/github.com/pdfcpu/pdfcpu/internal/corefont/metrics/standard.go new file mode 100644 index 0000000..3b98b52 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/internal/corefont/metrics/standard.go @@ -0,0 +1,680 @@ +// generated by "go run gen.go". DO NOT EDIT. + +package metrics + +import ( + "github.com/pdfcpu/pdfcpu/pkg/types" +) + +// WinAnsiGlyphMap is a glyph lookup table for CP1252 character codes. +// See Annex D.2 Latin Character Set and Encodings. +var WinAnsiGlyphMap = map[int]string{ + 32: "space", // U+0020 ' ' + 33: "exclam", // U+0021 '!' + 34: "quotedbl", // U+0022 '"' + 35: "numbersign", // U+0023 '#' + 36: "dollar", // U+0024 '$' + 37: "percent", // U+0025 '%' + 38: "ampersand", // U+0026 '&' + 39: "quotesingle", // U+0027 ''' + 40: "parenleft", // U+0028 '(' + 41: "parenright", // U+0029 ')' + 42: "asterisk", // U+002A '*' + 43: "plus", // U+002B '+' + 44: "comma", // U+002C ',' + 45: "hyphen", // U+002D '-' + 46: "period", // U+002E '.' + 47: "slash", // U+002F '/' + 48: "zero", // U+0030 '0' + 49: "one", // U+0031 '1' + 50: "two", // U+0032 '2' + 51: "three", // U+0033 '3' + 52: "four", // U+0034 '4' + 53: "five", // U+0035 '5' + 54: "six", // U+0036 '6' + 55: "seven", // U+0037 '7' + 56: "eight", // U+0038 '8' + 57: "nine", // U+0039 '9' + 58: "colon", // U+003A ':' + 59: "semicolon", // U+003B ';' + 60: "less", // U+003C '<' + 61: "equal", // U+003D '=' + 62: "greater", // U+003E '>' + 63: "question", // U+003F '?' + 64: "at", // U+0040 '@' + 65: "A", // U+0041 'A' + 66: "B", // U+0042 'B' + 67: "C", // U+0043 'C' + 68: "D", // U+0044 'D' + 69: "E", // U+0045 'E' + 70: "F", // U+0046 'F' + 71: "G", // U+0047 'G' + 72: "H", // U+0048 'H' + 73: "I", // U+0049 'I' + 74: "J", // U+004A 'J' + 75: "K", // U+004B 'K' + 76: "L", // U+004C 'L' + 77: "M", // U+004D 'M' + 78: "N", // U+004E 'N' + 79: "O", // U+004F 'O' + 80: "P", // U+0050 'P' + 81: "Q", // U+0051 'Q' + 82: "R", // U+0052 'R' + 83: "S", // U+0053 'S' + 84: "T", // U+0054 'T' + 85: "U", // U+0055 'U' + 86: "V", // U+0056 'V' + 87: "W", // U+0057 'W' + 88: "X", // U+0058 'X' + 89: "Y", // U+0059 'Y' + 90: "Z", // U+005A 'Z' + 91: "bracketleft", // U+005B '[' + 92: "backslash", // U+005C '\' + 93: "bracketright", // U+005D ']' + 94: "asciicircum", // U+005E '^' + 95: "underscore", // U+005F '_' + 96: "grave", // U+0060 '`' + 97: "a", // U+0061 'a' + 98: "b", // U+0062 'b' + 99: "c", // U+0063 'c' + 100: "d", // U+0064 'd' + 101: "e", // U+0065 'e' + 102: "f", // U+0066 'f' + 103: "g", // U+0067 'g' + 104: "h", // U+0068 'h' + 105: "i", // U+0069 'i' + 106: "j", // U+006A 'j' + 107: "k", // U+006B 'k' + 108: "l", // U+006C 'l' + 109: "m", // U+006D 'm' + 110: "n", // U+006E 'n' + 111: "o", // U+006F 'o' + 112: "p", // U+0070 'p' + 113: "q", // U+0071 'q' + 114: "r", // U+0072 'r' + 115: "s", // U+0073 's' + 116: "t", // U+0074 't' + 117: "u", // U+0075 'u' + 118: "v", // U+0076 'v' + 119: "w", // U+0077 'w' + 120: "x", // U+0078 'x' + 121: "y", // U+0079 'y' + 122: "z", // U+007A 'z' + 123: "braceleft", // U+007B '{' + 124: "bar", // U+007C '|' + 125: "braceright", // U+007D '}' + 126: "asciitilde", // U+007E '~' + 128: "Euro", // U+0080 + 130: "quotesinglbase", // U+0082 + 131: "florin", // U+0083 + 132: "quotedblbase", // U+0084 + 133: "ellipsis", // U+0085 + 134: "dagger", // U+0086 + 135: "daggerdbl", // U+0087 + 136: "circumflex", // U+0088 + 137: "perthousand", // U+0089 + 138: "Scaron", // U+008A + 139: "guilsinglleft", // U+008B + 140: "OE", // U+008C + 142: "Zcaron", // U+008E + 145: "quoteleft", // U+0091 + 146: "quoteright", // U+0092 + 147: "quotedblleft", // U+0093 + 148: "quotedblright", // U+0094 + 149: "bullet", // U+0095 + 150: "endash", // U+0096 + 151: "emdash", // U+0097 + 152: "tilde", // U+0098 + 153: "trademark", // U+0099 + 154: "scaron", // U+009A + 155: "guilsinglright", // U+009B + 156: "oe", // U+009C + 158: "zcaron", // U+009E + 159: "Ydieresis", // U+009F + 161: "exclamdown", // U+00A1 '¡' + 162: "cent", // U+00A2 '¢' + 163: "sterling", // U+00A3 '£' + 164: "currency", // U+00A4 '¤' + 165: "yen", // U+00A5 '¥' + 166: "brokenbar", // U+00A6 '¦' + 167: "section", // U+00A7 '§' + 168: "dieresis", // U+00A8 '¨' + 169: "copyright", // U+00A9 '©' + 170: "ordfeminine", // U+00AA 'ª' + 171: "guillemotleft", // U+00AB '«' + 172: "logicalnot", // U+00AC '¬' + 174: "registered", // U+00AE '®' + 175: "macron", // U+00AF '¯' + 176: "degree", // U+00B0 '°' + 177: "plusminus", // U+00B1 '±' + 178: "twosuperior", // U+00B2 '²' + 179: "threesuperior", // U+00B3 '³' + 180: "acute", // U+00B4 '´' + 181: "mu", // U+00B5 'µ' + 182: "paragraph", // U+00B6 '¶' + 183: "periodcentered", // U+00B7 '·' + 184: "cedilla", // U+00B8 '¸' + 185: "onesuperior", // U+00B9 '¹' + 186: "ordmasculine", // U+00BA 'º' + 187: "guillemotright", // U+00BB '»' + 188: "onequarter", // U+00BC '¼' + 189: "onehalf", // U+00BD '½' + 190: "threequarters", // U+00BE '¾' + 191: "questiondown", // U+00BF '¿' + 192: "Agrave", // U+00C0 'À' + 193: "Aacute", // U+00C1 'Á' + 194: "Acircumflex", // U+00C2 'Â' + 195: "Atilde", // U+00C3 'Ã' + 196: "Adieresis", // U+00C4 'Ä' + 197: "Aring", // U+00C5 'Å' + 198: "AE", // U+00C6 'Æ' + 199: "Ccedilla", // U+00C7 'Ç' + 200: "Egrave", // U+00C8 'È' + 201: "Eacute", // U+00C9 'É' + 202: "Ecircumflex", // U+00CA 'Ê' + 203: "Edieresis", // U+00CB 'Ë' + 204: "Igrave", // U+00CC 'Ì' + 205: "Iacute", // U+00CD 'Í' + 206: "Icircumflex", // U+00CE 'Î' + 207: "Idieresis", // U+00CF 'Ï' + 208: "Eth", // U+00D0 'Ð' + 209: "Ntilde", // U+00D1 'Ñ' + 210: "Ograve", // U+00D2 'Ò' + 211: "Oacute", // U+00D3 'Ó' + 212: "Ocircumflex", // U+00D4 'Ô' + 213: "Otilde", // U+00D5 'Õ' + 214: "Odieresis", // U+00D6 'Ö' + 215: "multiply", // U+00D7 '×' + 216: "Oslash", // U+00D8 'Ø' + 217: "Ugrave", // U+00D9 'Ù' + 218: "Uacute", // U+00DA 'Ú' + 219: "Ucircumflex", // U+00DB 'Û' + 220: "Udieresis", // U+00DC 'Ü' + 221: "Yacute", // U+00DD 'Ý' + 222: "Thorn", // U+00DE 'Þ' + 223: "germandbls", // U+00DF 'ß' + 224: "agrave", // U+00E0 'à' + 225: "aacute", // U+00E1 'á' + 226: "acircumflex", // U+00E2 'â' + 227: "atilde", // U+00E3 'ã' + 228: "adieresis", // U+00E4 'ä' + 229: "aring", // U+00E5 'å' + 230: "ae", // U+00E6 'æ' + 231: "ccedilla", // U+00E7 'ç' + 232: "egrave", // U+00E8 'è' + 233: "eacute", // U+00E9 'é' + 234: "ecircumflex", // U+00EA 'ê' + 235: "edieresis", // U+00EB 'ë' + 236: "igrave", // U+00EC 'ì' + 237: "iacute", // U+00ED 'í' + 238: "icircumflex", // U+00EE 'î' + 239: "idieresis", // U+00EF 'ï' + 240: "eth", // U+00F0 'ð' + 241: "ntilde", // U+00F1 'ñ' + 242: "ograve", // U+00F2 'ò' + 243: "oacute", // U+00F3 'ó' + 244: "ocircumflex", // U+00F4 'ô' + 245: "otilde", // U+00F5 'õ' + 246: "odieresis", // U+00F6 'ö' + 247: "divide", // U+00F7 '÷' + 248: "oslash", // U+00F8 'ø' + 249: "ugrave", // U+00F9 'ù' + 250: "uacute", // U+00FA 'ú' + 251: "ucircumflex", // U+00FB 'û' + 252: "udieresis", // U+00FC 'ü' + 253: "yacute", // U+00FD 'ý' + 254: "thorn", // U+00FE 'þ' + 255: "ydieresis", // U+00FF 'ÿ' +} + +// SymbolGlyphMap is a glyph lookup table for Symbol character codes. +// See Annex D.5 Symbol Set and Encoding. +var SymbolGlyphMap = map[int]string{ + 32: "space", // U+0020 ' ' + 33: "exclam", // U+0021 '!' + 34: "universal", // U+0022 '"' + 35: "numbersign", // U+0023 '#' + 36: "existential", // U+0024 '$' + 37: "percent", // U+0025 '%' + 38: "ampersand", // U+0026 '&' + 39: "suchthat", // U+0027 ''' + 40: "parenleft", // U+0028 '(' + 41: "parenright", // U+0029 ')' + 42: "asteriskmath", // U+002A '*' + 43: "plus", // U+002B '+' + 44: "comma", // U+002C ',' + 45: "minus", // U+002D '-' + 46: "period", // U+002E '.' + 47: "slash", // U+002F '/' + 48: "zero", // U+0030 '0' + 49: "one", // U+0031 '1' + 50: "two", // U+0032 '2' + 51: "three", // U+0033 '3' + 52: "four", // U+0034 '4' + 53: "five", // U+0035 '5' + 54: "six", // U+0036 '6' + 55: "seven", // U+0037 '7' + 56: "eight", // U+0038 '8' + 57: "nine", // U+0039 '9' + 58: "colon", // U+003A ':' + 59: "semicolon", // U+003B ';' + 60: "less", // U+003C '<' + 61: "equal", // U+003D '=' + 62: "greater", // U+003E '>' + 63: "question", // U+003F '?' + 64: "congruent", // U+0040 '@' + 65: "Alpha", // U+0041 'A' + 66: "Beta", // U+0042 'B' + 67: "Chi", // U+0043 'C' + 68: "Delta", // U+0044 'D' + 69: "Epsilon", // U+0045 'E' + 70: "Phi", // U+0046 'F' + 71: "Gamma", // U+0047 'G' + 72: "Eta", // U+0048 'H' + 73: "Iota", // U+0049 'I' + 74: "theta1", // U+004A 'J' + 75: "Kappa", // U+004B 'K' + 76: "Lambda", // U+004C 'L' + 77: "Mu", // U+004D 'M' + 78: "Nu", // U+004E 'N' + 79: "Omicron", // U+004F 'O' + 80: "Pi", // U+0050 'P' + 81: "Theta", // U+0051 'Q' + 82: "Rho", // U+0052 'R' + 83: "Sigma", // U+0053 'S' + 84: "Tau", // U+0054 'T' + 85: "Upsilon", // U+0055 'U' + 86: "sigma1", // U+0056 'V' + 87: "Omega", // U+0057 'W' + 88: "Xi", // U+0058 'X' + 89: "Psi", // U+0059 'Y' + 90: "Zeta", // U+005A 'Z' + 91: "bracketleft", // U+005B '[' + 92: "therefore", // U+005C '\' + 93: "bracketright", // U+005D ']' + 94: "perpendicular", // U+005E '^' + 95: "underscore", // U+005F '_' + 96: "radicalex", // U+0060 '`' + 97: "alpha", // U+0061 'a' + 98: "beta", // U+0062 'b' + 99: "chi", // U+0063 'c' + 100: "delta", // U+0064 'd' + 101: "epsilon", // U+0065 'e' + 102: "phi", // U+0066 'f' + 103: "gamma", // U+0067 'g' + 104: "eta", // U+0068 'h' + 105: "iota", // U+0069 'i' + 106: "phi1", // U+006A 'j' + 107: "kappa", // U+006B 'k' + 108: "lambda", // U+006C 'l' + 109: "mu", // U+006D 'm' + 110: "nu", // U+006E 'n' + 111: "omicron", // U+006F 'o' + 112: "pi", // U+0070 'p' + 113: "theta", // U+0071 'q' + 114: "rho", // U+0072 'r' + 115: "sigma", // U+0073 's' + 116: "tau", // U+0074 't' + 117: "upsilon", // U+0075 'u' + 118: "omega1", // U+0076 'v' + 119: "omega", // U+0077 'w' + 120: "xi", // U+0078 'x' + 121: "psi", // U+0079 'y' + 122: "zeta", // U+007A 'z' + 123: "braceleft", // U+007B '{' + 124: "bar", // U+007C '|' + 125: "braceright", // U+007D '}' + 126: "similar", // U+007E '~' + 160: "Euro", // U+00A0 + 161: "Upsilon1", // U+00A1 '¡' + 162: "minute", // U+00A2 '¢' + 163: "lessequal", // U+00A3 '£' + 164: "fraction", // U+00A4 '¤' + 165: "infinity", // U+00A5 '¥' + 166: "florin", // U+00A6 '¦' + 167: "club", // U+00A7 '§' + 168: "diamond", // U+00A8 '¨' + 169: "heart", // U+00A9 '©' + 170: "spade", // U+00AA 'ª' + 171: "arrowboth", // U+00AB '«' + 172: "arrowleft", // U+00AC '¬' + 173: "arrowup", // U+00AD + 174: "arrowright", // U+00AE '®' + 175: "arrowdown", // U+00AF '¯' + 176: "degree", // U+00B0 '°' + 177: "plusminus", // U+00B1 '±' + 178: "second", // U+00B2 '²' + 179: "greaterequal", // U+00B3 '³' + 180: "multiply", // U+00B4 '´' + 181: "proportional", // U+00B5 'µ' + 182: "partialdiff", // U+00B6 '¶' + 183: "bullet", // U+00B7 '·' + 184: "divide", // U+00B8 '¸' + 185: "notequal", // U+00B9 '¹' + 186: "equivalence", // U+00BA 'º' + 187: "approxequal", // U+00BB '»' + 188: "ellipsis", // U+00BC '¼' + 189: "arrowvertex", // U+00BD '½' + 190: "arrowhorizex", // U+00BE '¾' + 191: "carriagereturn", // U+00BF '¿' + 192: "aleph", // U+00C0 'À' + 193: "Ifraktur", // U+00C1 'Á' + 194: "Rfraktur", // U+00C2 'Â' + 195: "weierstrass", // U+00C3 'Ã' + 196: "circlemultiply", // U+00C4 'Ä' + 197: "circleplus", // U+00C5 'Å' + 198: "emptyset", // U+00C6 'Æ' + 199: "intersection", // U+00C7 'Ç' + 200: "union", // U+00C8 'È' + 201: "propersuperset", // U+00C9 'É' + 202: "reflexsuperset", // U+00CA 'Ê' + 203: "notsubset", // U+00CB 'Ë' + 204: "propersubset", // U+00CC 'Ì' + 205: "reflexsubset", // U+00CD 'Í' + 206: "element", // U+00CE 'Î' + 207: "notelement", // U+00CF 'Ï' + 208: "angle", // U+00D0 'Ð' + 209: "gradient", // U+00D1 'Ñ' + 210: "registerserif", // U+00D2 'Ò' + 211: "copyrightserif", // U+00D3 'Ó' + 212: "trademarkserif", // U+00D4 'Ô' + 213: "product", // U+00D5 'Õ' + 214: "radical", // U+00D6 'Ö' + 215: "dotmath", // U+00D7 '×' + 216: "logicalnot", // U+00D8 'Ø' + 217: "logicaland", // U+00D9 'Ù' + 218: "logicalor", // U+00DA 'Ú' + 219: "arrowdblboth", // U+00DB 'Û' + 220: "arrowdblleft", // U+00DC 'Ü' + 221: "arrowdblup", // U+00DD 'Ý' + 222: "arrowdblright", // U+00DE 'Þ' + 223: "arrowdbldown", // U+00DF 'ß' + 224: "lozenge", // U+00E0 'à' + 225: "angleleft", // U+00E1 'á' + 226: "registersans", // U+00E2 'â' + 227: "copyrightsans", // U+00E3 'ã' + 228: "trademarksans", // U+00E4 'ä' + 229: "summation", // U+00E5 'å' + 230: "parenlefttp", // U+00E6 'æ' + 231: "parenleftex", // U+00E7 'ç' + 232: "parenleftbt", // U+00E8 'è' + 233: "bracketlefttp", // U+00E9 'é' + 234: "bracketleftex", // U+00EA 'ê' + 235: "bracketleftbt", // U+00EB 'ë' + 236: "bracelefttp", // U+00EC 'ì' + 237: "braceleftmid", // U+00ED 'í' + 238: "braceleftbt", // U+00EE 'î' + 239: "braceex", // U+00EF 'ï' + 241: "angleright", // U+00F1 'ñ' + 242: "integral", // U+00F2 'ò' + 243: "integraltp", // U+00F3 'ó' + 244: "integralex", // U+00F4 'ô' + 245: "integralbt", // U+00F5 'õ' + 246: "parenrighttp", // U+00F6 'ö' + 247: "parenrightex", // U+00F7 '÷' + 248: "parenrightbt", // U+00F8 'ø' + 249: "bracketrighttp", // U+00F9 'ù' + 250: "bracketrightex", // U+00FA 'ú' + 251: "bracketrightbt", // U+00FB 'û' + 252: "bracerighttp", // U+00FC 'ü' + 253: "bracerightmid", // U+00FD 'ý' + 254: "bracerightbt", // U+00FE 'þ' +} + +// ZapfDingbatsGlyphMap is a glyph lookup table for ZapfDingbats character codes. +// See Annex D.6 ZapfDingbats Set and Encoding +var ZapfDingbatsGlyphMap = map[int]string{ + 32: "space", // U+0020 ' ' + 33: "a1", // U+0021 '!' + 34: "a2", // U+0022 '"' + 35: "a202", // U+0023 '#' + 36: "a3", // U+0024 '$' + 37: "a4", // U+0025 '%' + 38: "a5", // U+0026 '&' + 39: "a119", // U+0027 ''' + 40: "a118", // U+0028 '(' + 41: "a117", // U+0029 ')' + 42: "a11", // U+002A '*' + 43: "a12", // U+002B '+' + 44: "a13", // U+002C ',' + 45: "a14", // U+002D '-' + 46: "a15", // U+002E '.' + 47: "a16", // U+002F '/' + 48: "a105", // U+0030 '0' + 49: "a17", // U+0031 '1' + 50: "a18", // U+0032 '2' + 51: "a19", // U+0033 '3' + 52: "a20", // U+0034 '4' + 53: "a21", // U+0035 '5' + 54: "a22", // U+0036 '6' + 55: "a23", // U+0037 '7' + 56: "a24", // U+0038 '8' + 57: "a25", // U+0039 '9' + 58: "a26", // U+003A ':' + 59: "a27", // U+003B ';' + 60: "a28", // U+003C '<' + 61: "a6", // U+003D '=' + 62: "a7", // U+003E '>' + 63: "a8", // U+003F '?' + 64: "a9", // U+0040 '@' + 65: "a10", // U+0041 'A' + 66: "a29", // U+0042 'B' + 67: "a30", // U+0043 'C' + 68: "a31", // U+0044 'D' + 69: "a32", // U+0045 'E' + 70: "a33", // U+0046 'F' + 71: "a34", // U+0047 'G' + 72: "a35", // U+0048 'H' + 73: "a36", // U+0049 'I' + 74: "a37", // U+004A 'J' + 75: "a38", // U+004B 'K' + 76: "a39", // U+004C 'L' + 77: "a40", // U+004D 'M' + 78: "a41", // U+004E 'N' + 79: "a42", // U+004F 'O' + 80: "a43", // U+0050 'P' + 81: "a44", // U+0051 'Q' + 82: "a45", // U+0052 'R' + 83: "a46", // U+0053 'S' + 84: "a47", // U+0054 'T' + 85: "a48", // U+0055 'U' + 86: "a49", // U+0056 'V' + 87: "a50", // U+0057 'W' + 88: "a51", // U+0058 'X' + 89: "a52", // U+0059 'Y' + 90: "a53", // U+005A 'Z' + 91: "a54", // U+005B '[' + 92: "a55", // U+005C '\' + 93: "a56", // U+005D ']' + 94: "a57", // U+005E '^' + 95: "a58", // U+005F '_' + 96: "a59", // U+0060 '`' + 97: "a60", // U+0061 'a' + 98: "a61", // U+0062 'b' + 99: "a62", // U+0063 'c' + 100: "a63", // U+0064 'd' + 101: "a64", // U+0065 'e' + 102: "a65", // U+0066 'f' + 103: "a66", // U+0067 'g' + 104: "a67", // U+0068 'h' + 105: "a68", // U+0069 'i' + 106: "a69", // U+006A 'j' + 107: "a70", // U+006B 'k' + 108: "a71", // U+006C 'l' + 109: "a72", // U+006D 'm' + 110: "a73", // U+006E 'n' + 111: "a74", // U+006F 'o' + 112: "a203", // U+0070 'p' + 113: "a75", // U+0071 'q' + 114: "a204", // U+0072 'r' + 115: "a76", // U+0073 's' + 116: "a77", // U+0074 't' + 117: "a78", // U+0075 'u' + 118: "a79", // U+0076 'v' + 119: "a81", // U+0077 'w' + 120: "a82", // U+0078 'x' + 121: "a83", // U+0079 'y' + 122: "a84", // U+007A 'z' + 123: "a97", // U+007B '{' + 124: "a98", // U+007C '|' + 125: "a99", // U+007D '}' + 126: "a100", // U+007E '~' + 161: "a101", // U+00A1 '¡' + 162: "a102", // U+00A2 '¢' + 163: "a103", // U+00A3 '£' + 164: "a104", // U+00A4 '¤' + 165: "a106", // U+00A5 '¥' + 166: "a107", // U+00A6 '¦' + 167: "a108", // U+00A7 '§' + 168: "a112", // U+00A8 '¨' + 169: "a111", // U+00A9 '©' + 170: "a110", // U+00AA 'ª' + 171: "a109", // U+00AB '«' + 172: "a120", // U+00AC '¬' + 173: "a121", // U+00AD + 174: "a122", // U+00AE '®' + 175: "a123", // U+00AF '¯' + 176: "a124", // U+00B0 '°' + 177: "a125", // U+00B1 '±' + 178: "a126", // U+00B2 '²' + 179: "a127", // U+00B3 '³' + 180: "a128", // U+00B4 '´' + 181: "a129", // U+00B5 'µ' + 182: "a130", // U+00B6 '¶' + 183: "a131", // U+00B7 '·' + 184: "a132", // U+00B8 '¸' + 185: "a133", // U+00B9 '¹' + 186: "a134", // U+00BA 'º' + 187: "a135", // U+00BB '»' + 188: "a136", // U+00BC '¼' + 189: "a137", // U+00BD '½' + 190: "a138", // U+00BE '¾' + 191: "a139", // U+00BF '¿' + 192: "a140", // U+00C0 'À' + 193: "a141", // U+00C1 'Á' + 194: "a142", // U+00C2 'Â' + 195: "a143", // U+00C3 'Ã' + 196: "a144", // U+00C4 'Ä' + 197: "a145", // U+00C5 'Å' + 198: "a146", // U+00C6 'Æ' + 199: "a147", // U+00C7 'Ç' + 200: "a148", // U+00C8 'È' + 201: "a149", // U+00C9 'É' + 202: "a150", // U+00CA 'Ê' + 203: "a151", // U+00CB 'Ë' + 204: "a152", // U+00CC 'Ì' + 205: "a153", // U+00CD 'Í' + 206: "a154", // U+00CE 'Î' + 207: "a155", // U+00CF 'Ï' + 208: "a156", // U+00D0 'Ð' + 209: "a157", // U+00D1 'Ñ' + 210: "a158", // U+00D2 'Ò' + 211: "a159", // U+00D3 'Ó' + 212: "a160", // U+00D4 'Ô' + 213: "a161", // U+00D5 'Õ' + 214: "a163", // U+00D6 'Ö' + 215: "a164", // U+00D7 '×' + 216: "a196", // U+00D8 'Ø' + 217: "a165", // U+00D9 'Ù' + 218: "a192", // U+00DA 'Ú' + 219: "a166", // U+00DB 'Û' + 220: "a167", // U+00DC 'Ü' + 221: "a168", // U+00DD 'Ý' + 222: "a169", // U+00DE 'Þ' + 223: "a170", // U+00DF 'ß' + 224: "a171", // U+00E0 'à' + 225: "a172", // U+00E1 'á' + 226: "a173", // U+00E2 'â' + 227: "a162", // U+00E3 'ã' + 228: "a174", // U+00E4 'ä' + 229: "a175", // U+00E5 'å' + 230: "a176", // U+00E6 'æ' + 231: "a177", // U+00E7 'ç' + 232: "a178", // U+00E8 'è' + 233: "a179", // U+00E9 'é' + 234: "a193", // U+00EA 'ê' + 235: "a180", // U+00EB 'ë' + 236: "a199", // U+00EC 'ì' + 237: "a181", // U+00ED 'í' + 238: "a200", // U+00EE 'î' + 239: "a182", // U+00EF 'ï' + 241: "a201", // U+00F1 'ñ' + 242: "a183", // U+00F2 'ò' + 243: "a184", // U+00F3 'ó' + 244: "a197", // U+00F4 'ô' + 245: "a185", // U+00F5 'õ' + 246: "a194", // U+00F6 'ö' + 247: "a198", // U+00F7 '÷' + 248: "a186", // U+00F8 'ø' + 249: "a195", // U+00F9 'ù' + 250: "a187", // U+00FA 'ú' + 251: "a188", // U+00FB 'û' + 252: "a189", // U+00FC 'ü' + 253: "a190", // U+00FD 'ý' + 254: "a191", // U+00FE 'þ' +} + +type fontMetrics struct { + FBox *types.Rectangle // font box + W map[string]int // glyph widths +} + +// CoreFontMetrics represents font metrics for the Adobe standard type 1 core fonts. +var CoreFontMetrics = map[string]fontMetrics{ + "Courier-Bold": { + types.NewRectangle(-113.0, -250.0, 749.0, 801.0), + map[string]int{"space": 600, "exclam": 600, "quotedbl": 600, "numbersign": 600, "dollar": 600, "percent": 600, "ampersand": 600, "quoteright": 600, "parenleft": 600, "parenright": 600, "asterisk": 600, "plus": 600, "comma": 600, "hyphen": 600, "period": 600, "slash": 600, "zero": 600, "one": 600, "two": 600, "three": 600, "four": 600, "five": 600, "six": 600, "seven": 600, "eight": 600, "nine": 600, "colon": 600, "semicolon": 600, "less": 600, "equal": 600, "greater": 600, "question": 600, "at": 600, "A": 600, "B": 600, "C": 600, "D": 600, "E": 600, "F": 600, "G": 600, "H": 600, "I": 600, "J": 600, "K": 600, "L": 600, "M": 600, "N": 600, "O": 600, "P": 600, "Q": 600, "R": 600, "S": 600, "T": 600, "U": 600, "V": 600, "W": 600, "X": 600, "Y": 600, "Z": 600, "bracketleft": 600, "backslash": 600, "bracketright": 600, "asciicircum": 600, "underscore": 600, "quoteleft": 600, "a": 600, "b": 600, "c": 600, "d": 600, "e": 600, "f": 600, "g": 600, "h": 600, "i": 600, "j": 600, "k": 600, "l": 600, "m": 600, "n": 600, "o": 600, "p": 600, "q": 600, "r": 600, "s": 600, "t": 600, "u": 600, "v": 600, "w": 600, "x": 600, "y": 600, "z": 600, "braceleft": 600, "bar": 600, "braceright": 600, "asciitilde": 600, "exclamdown": 600, "cent": 600, "sterling": 600, "fraction": 600, "yen": 600, "florin": 600, "section": 600, "currency": 600, "quotesingle": 600, "quotedblleft": 600, "guillemotleft": 600, "guilsinglleft": 600, "guilsinglright": 600, "fi": 600, "fl": 600, "endash": 600, "dagger": 600, "daggerdbl": 600, "periodcentered": 600, "paragraph": 600, "bullet": 600, "quotesinglbase": 600, "quotedblbase": 600, "quotedblright": 600, "guillemotright": 600, "ellipsis": 600, "perthousand": 600, "questiondown": 600, "grave": 600, "acute": 600, "circumflex": 600, "tilde": 600, "macron": 600, "breve": 600, "dotaccent": 600, "dieresis": 600, "ring": 600, "cedilla": 600, "hungarumlaut": 600, "ogonek": 600, "caron": 600, "emdash": 600, "AE": 600, "ordfeminine": 600, "Lslash": 600, "Oslash": 600, "OE": 600, "ordmasculine": 600, "ae": 600, "dotlessi": 600, "lslash": 600, "oslash": 600, "oe": 600, "germandbls": 600, "Idieresis": 600, "eacute": 600, "abreve": 600, "uhungarumlaut": 600, "ecaron": 600, "Ydieresis": 600, "divide": 600, "Yacute": 600, "Acircumflex": 600, "aacute": 600, "Ucircumflex": 600, "yacute": 600, "scommaaccent": 600, "ecircumflex": 600, "Uring": 600, "Udieresis": 600, "aogonek": 600, "Uacute": 600, "uogonek": 600, "Edieresis": 600, "Dcroat": 600, "commaaccent": 600, "copyright": 600, "Emacron": 600, "ccaron": 600, "aring": 600, "Ncommaaccent": 600, "lacute": 600, "agrave": 600, "Tcommaaccent": 600, "Cacute": 600, "atilde": 600, "Edotaccent": 600, "scaron": 600, "scedilla": 600, "iacute": 600, "lozenge": 600, "Rcaron": 600, "Gcommaaccent": 600, "ucircumflex": 600, "acircumflex": 600, "Amacron": 600, "rcaron": 600, "ccedilla": 600, "Zdotaccent": 600, "Thorn": 600, "Omacron": 600, "Racute": 600, "Sacute": 600, "dcaron": 600, "Umacron": 600, "uring": 600, "threesuperior": 600, "Ograve": 600, "Agrave": 600, "Abreve": 600, "multiply": 600, "uacute": 600, "Tcaron": 600, "partialdiff": 600, "ydieresis": 600, "Nacute": 600, "icircumflex": 600, "Ecircumflex": 600, "adieresis": 600, "edieresis": 600, "cacute": 600, "nacute": 600, "umacron": 600, "Ncaron": 600, "Iacute": 600, "plusminus": 600, "brokenbar": 600, "registered": 600, "Gbreve": 600, "Idotaccent": 600, "summation": 600, "Egrave": 600, "racute": 600, "omacron": 600, "Zacute": 600, "Zcaron": 600, "greaterequal": 600, "Eth": 600, "Ccedilla": 600, "lcommaaccent": 600, "tcaron": 600, "eogonek": 600, "Uogonek": 600, "Aacute": 600, "Adieresis": 600, "egrave": 600, "zacute": 600, "iogonek": 600, "Oacute": 600, "oacute": 600, "amacron": 600, "sacute": 600, "idieresis": 600, "Ocircumflex": 600, "Ugrave": 600, "Delta": 600, "thorn": 600, "twosuperior": 600, "Odieresis": 600, "mu": 600, "igrave": 600, "ohungarumlaut": 600, "Eogonek": 600, "dcroat": 600, "threequarters": 600, "Scedilla": 600, "lcaron": 600, "Kcommaaccent": 600, "Lacute": 600, "trademark": 600, "edotaccent": 600, "Igrave": 600, "Imacron": 600, "Lcaron": 600, "onehalf": 600, "lessequal": 600, "ocircumflex": 600, "ntilde": 600, "Uhungarumlaut": 600, "Eacute": 600, "emacron": 600, "gbreve": 600, "onequarter": 600, "Scaron": 600, "Scommaaccent": 600, "Ohungarumlaut": 600, "degree": 600, "ograve": 600, "Ccaron": 600, "ugrave": 600, "radical": 600, "Dcaron": 600, "rcommaaccent": 600, "Ntilde": 600, "otilde": 600, "Rcommaaccent": 600, "Lcommaaccent": 600, "Atilde": 600, "Aogonek": 600, "Aring": 600, "Otilde": 600, "zdotaccent": 600, "Ecaron": 600, "Iogonek": 600, "kcommaaccent": 600, "minus": 600, "Icircumflex": 600, "ncaron": 600, "tcommaaccent": 600, "logicalnot": 600, "odieresis": 600, "udieresis": 600, "notequal": 600, "gcommaaccent": 600, "eth": 600, "zcaron": 600, "ncommaaccent": 600, "onesuperior": 600, "imacron": 600, "Euro": 600}, + }, + "Courier-BoldOblique": { + types.NewRectangle(-57.0, -250.0, 869.0, 801.0), + map[string]int{"space": 600, "exclam": 600, "quotedbl": 600, "numbersign": 600, "dollar": 600, "percent": 600, "ampersand": 600, "quoteright": 600, "parenleft": 600, "parenright": 600, "asterisk": 600, "plus": 600, "comma": 600, "hyphen": 600, "period": 600, "slash": 600, "zero": 600, "one": 600, "two": 600, "three": 600, "four": 600, "five": 600, "six": 600, "seven": 600, "eight": 600, "nine": 600, "colon": 600, "semicolon": 600, "less": 600, "equal": 600, "greater": 600, "question": 600, "at": 600, "A": 600, "B": 600, "C": 600, "D": 600, "E": 600, "F": 600, "G": 600, "H": 600, "I": 600, "J": 600, "K": 600, "L": 600, "M": 600, "N": 600, "O": 600, "P": 600, "Q": 600, "R": 600, "S": 600, "T": 600, "U": 600, "V": 600, "W": 600, "X": 600, "Y": 600, "Z": 600, "bracketleft": 600, "backslash": 600, "bracketright": 600, "asciicircum": 600, "underscore": 600, "quoteleft": 600, "a": 600, "b": 600, "c": 600, "d": 600, "e": 600, "f": 600, "g": 600, "h": 600, "i": 600, "j": 600, "k": 600, "l": 600, "m": 600, "n": 600, "o": 600, "p": 600, "q": 600, "r": 600, "s": 600, "t": 600, "u": 600, "v": 600, "w": 600, "x": 600, "y": 600, "z": 600, "braceleft": 600, "bar": 600, "braceright": 600, "asciitilde": 600, "exclamdown": 600, "cent": 600, "sterling": 600, "fraction": 600, "yen": 600, "florin": 600, "section": 600, "currency": 600, "quotesingle": 600, "quotedblleft": 600, "guillemotleft": 600, "guilsinglleft": 600, "guilsinglright": 600, "fi": 600, "fl": 600, "endash": 600, "dagger": 600, "daggerdbl": 600, "periodcentered": 600, "paragraph": 600, "bullet": 600, "quotesinglbase": 600, "quotedblbase": 600, "quotedblright": 600, "guillemotright": 600, "ellipsis": 600, "perthousand": 600, "questiondown": 600, "grave": 600, "acute": 600, "circumflex": 600, "tilde": 600, "macron": 600, "breve": 600, "dotaccent": 600, "dieresis": 600, "ring": 600, "cedilla": 600, "hungarumlaut": 600, "ogonek": 600, "caron": 600, "emdash": 600, "AE": 600, "ordfeminine": 600, "Lslash": 600, "Oslash": 600, "OE": 600, "ordmasculine": 600, "ae": 600, "dotlessi": 600, "lslash": 600, "oslash": 600, "oe": 600, "germandbls": 600, "Idieresis": 600, "eacute": 600, "abreve": 600, "uhungarumlaut": 600, "ecaron": 600, "Ydieresis": 600, "divide": 600, "Yacute": 600, "Acircumflex": 600, "aacute": 600, "Ucircumflex": 600, "yacute": 600, "scommaaccent": 600, "ecircumflex": 600, "Uring": 600, "Udieresis": 600, "aogonek": 600, "Uacute": 600, "uogonek": 600, "Edieresis": 600, "Dcroat": 600, "commaaccent": 600, "copyright": 600, "Emacron": 600, "ccaron": 600, "aring": 600, "Ncommaaccent": 600, "lacute": 600, "agrave": 600, "Tcommaaccent": 600, "Cacute": 600, "atilde": 600, "Edotaccent": 600, "scaron": 600, "scedilla": 600, "iacute": 600, "lozenge": 600, "Rcaron": 600, "Gcommaaccent": 600, "ucircumflex": 600, "acircumflex": 600, "Amacron": 600, "rcaron": 600, "ccedilla": 600, "Zdotaccent": 600, "Thorn": 600, "Omacron": 600, "Racute": 600, "Sacute": 600, "dcaron": 600, "Umacron": 600, "uring": 600, "threesuperior": 600, "Ograve": 600, "Agrave": 600, "Abreve": 600, "multiply": 600, "uacute": 600, "Tcaron": 600, "partialdiff": 600, "ydieresis": 600, "Nacute": 600, "icircumflex": 600, "Ecircumflex": 600, "adieresis": 600, "edieresis": 600, "cacute": 600, "nacute": 600, "umacron": 600, "Ncaron": 600, "Iacute": 600, "plusminus": 600, "brokenbar": 600, "registered": 600, "Gbreve": 600, "Idotaccent": 600, "summation": 600, "Egrave": 600, "racute": 600, "omacron": 600, "Zacute": 600, "Zcaron": 600, "greaterequal": 600, "Eth": 600, "Ccedilla": 600, "lcommaaccent": 600, "tcaron": 600, "eogonek": 600, "Uogonek": 600, "Aacute": 600, "Adieresis": 600, "egrave": 600, "zacute": 600, "iogonek": 600, "Oacute": 600, "oacute": 600, "amacron": 600, "sacute": 600, "idieresis": 600, "Ocircumflex": 600, "Ugrave": 600, "Delta": 600, "thorn": 600, "twosuperior": 600, "Odieresis": 600, "mu": 600, "igrave": 600, "ohungarumlaut": 600, "Eogonek": 600, "dcroat": 600, "threequarters": 600, "Scedilla": 600, "lcaron": 600, "Kcommaaccent": 600, "Lacute": 600, "trademark": 600, "edotaccent": 600, "Igrave": 600, "Imacron": 600, "Lcaron": 600, "onehalf": 600, "lessequal": 600, "ocircumflex": 600, "ntilde": 600, "Uhungarumlaut": 600, "Eacute": 600, "emacron": 600, "gbreve": 600, "onequarter": 600, "Scaron": 600, "Scommaaccent": 600, "Ohungarumlaut": 600, "degree": 600, "ograve": 600, "Ccaron": 600, "ugrave": 600, "radical": 600, "Dcaron": 600, "rcommaaccent": 600, "Ntilde": 600, "otilde": 600, "Rcommaaccent": 600, "Lcommaaccent": 600, "Atilde": 600, "Aogonek": 600, "Aring": 600, "Otilde": 600, "zdotaccent": 600, "Ecaron": 600, "Iogonek": 600, "kcommaaccent": 600, "minus": 600, "Icircumflex": 600, "ncaron": 600, "tcommaaccent": 600, "logicalnot": 600, "odieresis": 600, "udieresis": 600, "notequal": 600, "gcommaaccent": 600, "eth": 600, "zcaron": 600, "ncommaaccent": 600, "onesuperior": 600, "imacron": 600, "Euro": 600}, + }, + "Courier-Oblique": { + types.NewRectangle(-27.0, -250.0, 849.0, 805.0), + map[string]int{"space": 600, "exclam": 600, "quotedbl": 600, "numbersign": 600, "dollar": 600, "percent": 600, "ampersand": 600, "quoteright": 600, "parenleft": 600, "parenright": 600, "asterisk": 600, "plus": 600, "comma": 600, "hyphen": 600, "period": 600, "slash": 600, "zero": 600, "one": 600, "two": 600, "three": 600, "four": 600, "five": 600, "six": 600, "seven": 600, "eight": 600, "nine": 600, "colon": 600, "semicolon": 600, "less": 600, "equal": 600, "greater": 600, "question": 600, "at": 600, "A": 600, "B": 600, "C": 600, "D": 600, "E": 600, "F": 600, "G": 600, "H": 600, "I": 600, "J": 600, "K": 600, "L": 600, "M": 600, "N": 600, "O": 600, "P": 600, "Q": 600, "R": 600, "S": 600, "T": 600, "U": 600, "V": 600, "W": 600, "X": 600, "Y": 600, "Z": 600, "bracketleft": 600, "backslash": 600, "bracketright": 600, "asciicircum": 600, "underscore": 600, "quoteleft": 600, "a": 600, "b": 600, "c": 600, "d": 600, "e": 600, "f": 600, "g": 600, "h": 600, "i": 600, "j": 600, "k": 600, "l": 600, "m": 600, "n": 600, "o": 600, "p": 600, "q": 600, "r": 600, "s": 600, "t": 600, "u": 600, "v": 600, "w": 600, "x": 600, "y": 600, "z": 600, "braceleft": 600, "bar": 600, "braceright": 600, "asciitilde": 600, "exclamdown": 600, "cent": 600, "sterling": 600, "fraction": 600, "yen": 600, "florin": 600, "section": 600, "currency": 600, "quotesingle": 600, "quotedblleft": 600, "guillemotleft": 600, "guilsinglleft": 600, "guilsinglright": 600, "fi": 600, "fl": 600, "endash": 600, "dagger": 600, "daggerdbl": 600, "periodcentered": 600, "paragraph": 600, "bullet": 600, "quotesinglbase": 600, "quotedblbase": 600, "quotedblright": 600, "guillemotright": 600, "ellipsis": 600, "perthousand": 600, "questiondown": 600, "grave": 600, "acute": 600, "circumflex": 600, "tilde": 600, "macron": 600, "breve": 600, "dotaccent": 600, "dieresis": 600, "ring": 600, "cedilla": 600, "hungarumlaut": 600, "ogonek": 600, "caron": 600, "emdash": 600, "AE": 600, "ordfeminine": 600, "Lslash": 600, "Oslash": 600, "OE": 600, "ordmasculine": 600, "ae": 600, "dotlessi": 600, "lslash": 600, "oslash": 600, "oe": 600, "germandbls": 600, "Idieresis": 600, "eacute": 600, "abreve": 600, "uhungarumlaut": 600, "ecaron": 600, "Ydieresis": 600, "divide": 600, "Yacute": 600, "Acircumflex": 600, "aacute": 600, "Ucircumflex": 600, "yacute": 600, "scommaaccent": 600, "ecircumflex": 600, "Uring": 600, "Udieresis": 600, "aogonek": 600, "Uacute": 600, "uogonek": 600, "Edieresis": 600, "Dcroat": 600, "commaaccent": 600, "copyright": 600, "Emacron": 600, "ccaron": 600, "aring": 600, "Ncommaaccent": 600, "lacute": 600, "agrave": 600, "Tcommaaccent": 600, "Cacute": 600, "atilde": 600, "Edotaccent": 600, "scaron": 600, "scedilla": 600, "iacute": 600, "lozenge": 600, "Rcaron": 600, "Gcommaaccent": 600, "ucircumflex": 600, "acircumflex": 600, "Amacron": 600, "rcaron": 600, "ccedilla": 600, "Zdotaccent": 600, "Thorn": 600, "Omacron": 600, "Racute": 600, "Sacute": 600, "dcaron": 600, "Umacron": 600, "uring": 600, "threesuperior": 600, "Ograve": 600, "Agrave": 600, "Abreve": 600, "multiply": 600, "uacute": 600, "Tcaron": 600, "partialdiff": 600, "ydieresis": 600, "Nacute": 600, "icircumflex": 600, "Ecircumflex": 600, "adieresis": 600, "edieresis": 600, "cacute": 600, "nacute": 600, "umacron": 600, "Ncaron": 600, "Iacute": 600, "plusminus": 600, "brokenbar": 600, "registered": 600, "Gbreve": 600, "Idotaccent": 600, "summation": 600, "Egrave": 600, "racute": 600, "omacron": 600, "Zacute": 600, "Zcaron": 600, "greaterequal": 600, "Eth": 600, "Ccedilla": 600, "lcommaaccent": 600, "tcaron": 600, "eogonek": 600, "Uogonek": 600, "Aacute": 600, "Adieresis": 600, "egrave": 600, "zacute": 600, "iogonek": 600, "Oacute": 600, "oacute": 600, "amacron": 600, "sacute": 600, "idieresis": 600, "Ocircumflex": 600, "Ugrave": 600, "Delta": 600, "thorn": 600, "twosuperior": 600, "Odieresis": 600, "mu": 600, "igrave": 600, "ohungarumlaut": 600, "Eogonek": 600, "dcroat": 600, "threequarters": 600, "Scedilla": 600, "lcaron": 600, "Kcommaaccent": 600, "Lacute": 600, "trademark": 600, "edotaccent": 600, "Igrave": 600, "Imacron": 600, "Lcaron": 600, "onehalf": 600, "lessequal": 600, "ocircumflex": 600, "ntilde": 600, "Uhungarumlaut": 600, "Eacute": 600, "emacron": 600, "gbreve": 600, "onequarter": 600, "Scaron": 600, "Scommaaccent": 600, "Ohungarumlaut": 600, "degree": 600, "ograve": 600, "Ccaron": 600, "ugrave": 600, "radical": 600, "Dcaron": 600, "rcommaaccent": 600, "Ntilde": 600, "otilde": 600, "Rcommaaccent": 600, "Lcommaaccent": 600, "Atilde": 600, "Aogonek": 600, "Aring": 600, "Otilde": 600, "zdotaccent": 600, "Ecaron": 600, "Iogonek": 600, "kcommaaccent": 600, "minus": 600, "Icircumflex": 600, "ncaron": 600, "tcommaaccent": 600, "logicalnot": 600, "odieresis": 600, "udieresis": 600, "notequal": 600, "gcommaaccent": 600, "eth": 600, "zcaron": 600, "ncommaaccent": 600, "onesuperior": 600, "imacron": 600, "Euro": 600}, + }, + "Courier": { + types.NewRectangle(-23.0, -250.0, 715.0, 805.0), + map[string]int{"space": 600, "exclam": 600, "quotedbl": 600, "numbersign": 600, "dollar": 600, "percent": 600, "ampersand": 600, "quoteright": 600, "parenleft": 600, "parenright": 600, "asterisk": 600, "plus": 600, "comma": 600, "hyphen": 600, "period": 600, "slash": 600, "zero": 600, "one": 600, "two": 600, "three": 600, "four": 600, "five": 600, "six": 600, "seven": 600, "eight": 600, "nine": 600, "colon": 600, "semicolon": 600, "less": 600, "equal": 600, "greater": 600, "question": 600, "at": 600, "A": 600, "B": 600, "C": 600, "D": 600, "E": 600, "F": 600, "G": 600, "H": 600, "I": 600, "J": 600, "K": 600, "L": 600, "M": 600, "N": 600, "O": 600, "P": 600, "Q": 600, "R": 600, "S": 600, "T": 600, "U": 600, "V": 600, "W": 600, "X": 600, "Y": 600, "Z": 600, "bracketleft": 600, "backslash": 600, "bracketright": 600, "asciicircum": 600, "underscore": 600, "quoteleft": 600, "a": 600, "b": 600, "c": 600, "d": 600, "e": 600, "f": 600, "g": 600, "h": 600, "i": 600, "j": 600, "k": 600, "l": 600, "m": 600, "n": 600, "o": 600, "p": 600, "q": 600, "r": 600, "s": 600, "t": 600, "u": 600, "v": 600, "w": 600, "x": 600, "y": 600, "z": 600, "braceleft": 600, "bar": 600, "braceright": 600, "asciitilde": 600, "exclamdown": 600, "cent": 600, "sterling": 600, "fraction": 600, "yen": 600, "florin": 600, "section": 600, "currency": 600, "quotesingle": 600, "quotedblleft": 600, "guillemotleft": 600, "guilsinglleft": 600, "guilsinglright": 600, "fi": 600, "fl": 600, "endash": 600, "dagger": 600, "daggerdbl": 600, "periodcentered": 600, "paragraph": 600, "bullet": 600, "quotesinglbase": 600, "quotedblbase": 600, "quotedblright": 600, "guillemotright": 600, "ellipsis": 600, "perthousand": 600, "questiondown": 600, "grave": 600, "acute": 600, "circumflex": 600, "tilde": 600, "macron": 600, "breve": 600, "dotaccent": 600, "dieresis": 600, "ring": 600, "cedilla": 600, "hungarumlaut": 600, "ogonek": 600, "caron": 600, "emdash": 600, "AE": 600, "ordfeminine": 600, "Lslash": 600, "Oslash": 600, "OE": 600, "ordmasculine": 600, "ae": 600, "dotlessi": 600, "lslash": 600, "oslash": 600, "oe": 600, "germandbls": 600, "Idieresis": 600, "eacute": 600, "abreve": 600, "uhungarumlaut": 600, "ecaron": 600, "Ydieresis": 600, "divide": 600, "Yacute": 600, "Acircumflex": 600, "aacute": 600, "Ucircumflex": 600, "yacute": 600, "scommaaccent": 600, "ecircumflex": 600, "Uring": 600, "Udieresis": 600, "aogonek": 600, "Uacute": 600, "uogonek": 600, "Edieresis": 600, "Dcroat": 600, "commaaccent": 600, "copyright": 600, "Emacron": 600, "ccaron": 600, "aring": 600, "Ncommaaccent": 600, "lacute": 600, "agrave": 600, "Tcommaaccent": 600, "Cacute": 600, "atilde": 600, "Edotaccent": 600, "scaron": 600, "scedilla": 600, "iacute": 600, "lozenge": 600, "Rcaron": 600, "Gcommaaccent": 600, "ucircumflex": 600, "acircumflex": 600, "Amacron": 600, "rcaron": 600, "ccedilla": 600, "Zdotaccent": 600, "Thorn": 600, "Omacron": 600, "Racute": 600, "Sacute": 600, "dcaron": 600, "Umacron": 600, "uring": 600, "threesuperior": 600, "Ograve": 600, "Agrave": 600, "Abreve": 600, "multiply": 600, "uacute": 600, "Tcaron": 600, "partialdiff": 600, "ydieresis": 600, "Nacute": 600, "icircumflex": 600, "Ecircumflex": 600, "adieresis": 600, "edieresis": 600, "cacute": 600, "nacute": 600, "umacron": 600, "Ncaron": 600, "Iacute": 600, "plusminus": 600, "brokenbar": 600, "registered": 600, "Gbreve": 600, "Idotaccent": 600, "summation": 600, "Egrave": 600, "racute": 600, "omacron": 600, "Zacute": 600, "Zcaron": 600, "greaterequal": 600, "Eth": 600, "Ccedilla": 600, "lcommaaccent": 600, "tcaron": 600, "eogonek": 600, "Uogonek": 600, "Aacute": 600, "Adieresis": 600, "egrave": 600, "zacute": 600, "iogonek": 600, "Oacute": 600, "oacute": 600, "amacron": 600, "sacute": 600, "idieresis": 600, "Ocircumflex": 600, "Ugrave": 600, "Delta": 600, "thorn": 600, "twosuperior": 600, "Odieresis": 600, "mu": 600, "igrave": 600, "ohungarumlaut": 600, "Eogonek": 600, "dcroat": 600, "threequarters": 600, "Scedilla": 600, "lcaron": 600, "Kcommaaccent": 600, "Lacute": 600, "trademark": 600, "edotaccent": 600, "Igrave": 600, "Imacron": 600, "Lcaron": 600, "onehalf": 600, "lessequal": 600, "ocircumflex": 600, "ntilde": 600, "Uhungarumlaut": 600, "Eacute": 600, "emacron": 600, "gbreve": 600, "onequarter": 600, "Scaron": 600, "Scommaaccent": 600, "Ohungarumlaut": 600, "degree": 600, "ograve": 600, "Ccaron": 600, "ugrave": 600, "radical": 600, "Dcaron": 600, "rcommaaccent": 600, "Ntilde": 600, "otilde": 600, "Rcommaaccent": 600, "Lcommaaccent": 600, "Atilde": 600, "Aogonek": 600, "Aring": 600, "Otilde": 600, "zdotaccent": 600, "Ecaron": 600, "Iogonek": 600, "kcommaaccent": 600, "minus": 600, "Icircumflex": 600, "ncaron": 600, "tcommaaccent": 600, "logicalnot": 600, "odieresis": 600, "udieresis": 600, "notequal": 600, "gcommaaccent": 600, "eth": 600, "zcaron": 600, "ncommaaccent": 600, "onesuperior": 600, "imacron": 600, "Euro": 600}, + }, + "Helvetica-Bold": { + types.NewRectangle(-170.0, -228.0, 1003.0, 962.0), + map[string]int{"space": 278, "exclam": 333, "quotedbl": 474, "numbersign": 556, "dollar": 556, "percent": 889, "ampersand": 722, "quoteright": 278, "parenleft": 333, "parenright": 333, "asterisk": 389, "plus": 584, "comma": 278, "hyphen": 333, "period": 278, "slash": 278, "zero": 556, "one": 556, "two": 556, "three": 556, "four": 556, "five": 556, "six": 556, "seven": 556, "eight": 556, "nine": 556, "colon": 333, "semicolon": 333, "less": 584, "equal": 584, "greater": 584, "question": 611, "at": 975, "A": 722, "B": 722, "C": 722, "D": 722, "E": 667, "F": 611, "G": 778, "H": 722, "I": 278, "J": 556, "K": 722, "L": 611, "M": 833, "N": 722, "O": 778, "P": 667, "Q": 778, "R": 722, "S": 667, "T": 611, "U": 722, "V": 667, "W": 944, "X": 667, "Y": 667, "Z": 611, "bracketleft": 333, "backslash": 278, "bracketright": 333, "asciicircum": 584, "underscore": 556, "quoteleft": 278, "a": 556, "b": 611, "c": 556, "d": 611, "e": 556, "f": 333, "g": 611, "h": 611, "i": 278, "j": 278, "k": 556, "l": 278, "m": 889, "n": 611, "o": 611, "p": 611, "q": 611, "r": 389, "s": 556, "t": 333, "u": 611, "v": 556, "w": 778, "x": 556, "y": 556, "z": 500, "braceleft": 389, "bar": 280, "braceright": 389, "asciitilde": 584, "exclamdown": 333, "cent": 556, "sterling": 556, "fraction": 167, "yen": 556, "florin": 556, "section": 556, "currency": 556, "quotesingle": 238, "quotedblleft": 500, "guillemotleft": 556, "guilsinglleft": 333, "guilsinglright": 333, "fi": 611, "fl": 611, "endash": 556, "dagger": 556, "daggerdbl": 556, "periodcentered": 278, "paragraph": 556, "bullet": 350, "quotesinglbase": 278, "quotedblbase": 500, "quotedblright": 500, "guillemotright": 556, "ellipsis": 1000, "perthousand": 1000, "questiondown": 611, "grave": 333, "acute": 333, "circumflex": 333, "tilde": 333, "macron": 333, "breve": 333, "dotaccent": 333, "dieresis": 333, "ring": 333, "cedilla": 333, "hungarumlaut": 333, "ogonek": 333, "caron": 333, "emdash": 1000, "AE": 1000, "ordfeminine": 370, "Lslash": 611, "Oslash": 778, "OE": 1000, "ordmasculine": 365, "ae": 889, "dotlessi": 278, "lslash": 278, "oslash": 611, "oe": 944, "germandbls": 611, "Idieresis": 278, "eacute": 556, "abreve": 556, "uhungarumlaut": 611, "ecaron": 556, "Ydieresis": 667, "divide": 584, "Yacute": 667, "Acircumflex": 722, "aacute": 556, "Ucircumflex": 722, "yacute": 556, "scommaaccent": 556, "ecircumflex": 556, "Uring": 722, "Udieresis": 722, "aogonek": 556, "Uacute": 722, "uogonek": 611, "Edieresis": 667, "Dcroat": 722, "commaaccent": 250, "copyright": 737, "Emacron": 667, "ccaron": 556, "aring": 556, "Ncommaaccent": 722, "lacute": 278, "agrave": 556, "Tcommaaccent": 611, "Cacute": 722, "atilde": 556, "Edotaccent": 667, "scaron": 556, "scedilla": 556, "iacute": 278, "lozenge": 494, "Rcaron": 722, "Gcommaaccent": 778, "ucircumflex": 611, "acircumflex": 556, "Amacron": 722, "rcaron": 389, "ccedilla": 556, "Zdotaccent": 611, "Thorn": 667, "Omacron": 778, "Racute": 722, "Sacute": 667, "dcaron": 743, "Umacron": 722, "uring": 611, "threesuperior": 333, "Ograve": 778, "Agrave": 722, "Abreve": 722, "multiply": 584, "uacute": 611, "Tcaron": 611, "partialdiff": 494, "ydieresis": 556, "Nacute": 722, "icircumflex": 278, "Ecircumflex": 667, "adieresis": 556, "edieresis": 556, "cacute": 556, "nacute": 611, "umacron": 611, "Ncaron": 722, "Iacute": 278, "plusminus": 584, "brokenbar": 280, "registered": 737, "Gbreve": 778, "Idotaccent": 278, "summation": 600, "Egrave": 667, "racute": 389, "omacron": 611, "Zacute": 611, "Zcaron": 611, "greaterequal": 549, "Eth": 722, "Ccedilla": 722, "lcommaaccent": 278, "tcaron": 389, "eogonek": 556, "Uogonek": 722, "Aacute": 722, "Adieresis": 722, "egrave": 556, "zacute": 500, "iogonek": 278, "Oacute": 778, "oacute": 611, "amacron": 556, "sacute": 556, "idieresis": 278, "Ocircumflex": 778, "Ugrave": 722, "Delta": 612, "thorn": 611, "twosuperior": 333, "Odieresis": 778, "mu": 611, "igrave": 278, "ohungarumlaut": 611, "Eogonek": 667, "dcroat": 611, "threequarters": 834, "Scedilla": 667, "lcaron": 400, "Kcommaaccent": 722, "Lacute": 611, "trademark": 1000, "edotaccent": 556, "Igrave": 278, "Imacron": 278, "Lcaron": 611, "onehalf": 834, "lessequal": 549, "ocircumflex": 611, "ntilde": 611, "Uhungarumlaut": 722, "Eacute": 667, "emacron": 556, "gbreve": 611, "onequarter": 834, "Scaron": 667, "Scommaaccent": 667, "Ohungarumlaut": 778, "degree": 400, "ograve": 611, "Ccaron": 722, "ugrave": 611, "radical": 549, "Dcaron": 722, "rcommaaccent": 389, "Ntilde": 722, "otilde": 611, "Rcommaaccent": 722, "Lcommaaccent": 611, "Atilde": 722, "Aogonek": 722, "Aring": 722, "Otilde": 778, "zdotaccent": 500, "Ecaron": 667, "Iogonek": 278, "kcommaaccent": 556, "minus": 584, "Icircumflex": 278, "ncaron": 611, "tcommaaccent": 333, "logicalnot": 584, "odieresis": 611, "udieresis": 611, "notequal": 549, "gcommaaccent": 611, "eth": 611, "zcaron": 500, "ncommaaccent": 611, "onesuperior": 333, "imacron": 278, "Euro": 556}, + }, + "Helvetica-BoldOblique": { + types.NewRectangle(-174.0, -228.0, 1114.0, 962.0), + map[string]int{"space": 278, "exclam": 333, "quotedbl": 474, "numbersign": 556, "dollar": 556, "percent": 889, "ampersand": 722, "quoteright": 278, "parenleft": 333, "parenright": 333, "asterisk": 389, "plus": 584, "comma": 278, "hyphen": 333, "period": 278, "slash": 278, "zero": 556, "one": 556, "two": 556, "three": 556, "four": 556, "five": 556, "six": 556, "seven": 556, "eight": 556, "nine": 556, "colon": 333, "semicolon": 333, "less": 584, "equal": 584, "greater": 584, "question": 611, "at": 975, "A": 722, "B": 722, "C": 722, "D": 722, "E": 667, "F": 611, "G": 778, "H": 722, "I": 278, "J": 556, "K": 722, "L": 611, "M": 833, "N": 722, "O": 778, "P": 667, "Q": 778, "R": 722, "S": 667, "T": 611, "U": 722, "V": 667, "W": 944, "X": 667, "Y": 667, "Z": 611, "bracketleft": 333, "backslash": 278, "bracketright": 333, "asciicircum": 584, "underscore": 556, "quoteleft": 278, "a": 556, "b": 611, "c": 556, "d": 611, "e": 556, "f": 333, "g": 611, "h": 611, "i": 278, "j": 278, "k": 556, "l": 278, "m": 889, "n": 611, "o": 611, "p": 611, "q": 611, "r": 389, "s": 556, "t": 333, "u": 611, "v": 556, "w": 778, "x": 556, "y": 556, "z": 500, "braceleft": 389, "bar": 280, "braceright": 389, "asciitilde": 584, "exclamdown": 333, "cent": 556, "sterling": 556, "fraction": 167, "yen": 556, "florin": 556, "section": 556, "currency": 556, "quotesingle": 238, "quotedblleft": 500, "guillemotleft": 556, "guilsinglleft": 333, "guilsinglright": 333, "fi": 611, "fl": 611, "endash": 556, "dagger": 556, "daggerdbl": 556, "periodcentered": 278, "paragraph": 556, "bullet": 350, "quotesinglbase": 278, "quotedblbase": 500, "quotedblright": 500, "guillemotright": 556, "ellipsis": 1000, "perthousand": 1000, "questiondown": 611, "grave": 333, "acute": 333, "circumflex": 333, "tilde": 333, "macron": 333, "breve": 333, "dotaccent": 333, "dieresis": 333, "ring": 333, "cedilla": 333, "hungarumlaut": 333, "ogonek": 333, "caron": 333, "emdash": 1000, "AE": 1000, "ordfeminine": 370, "Lslash": 611, "Oslash": 778, "OE": 1000, "ordmasculine": 365, "ae": 889, "dotlessi": 278, "lslash": 278, "oslash": 611, "oe": 944, "germandbls": 611, "Idieresis": 278, "eacute": 556, "abreve": 556, "uhungarumlaut": 611, "ecaron": 556, "Ydieresis": 667, "divide": 584, "Yacute": 667, "Acircumflex": 722, "aacute": 556, "Ucircumflex": 722, "yacute": 556, "scommaaccent": 556, "ecircumflex": 556, "Uring": 722, "Udieresis": 722, "aogonek": 556, "Uacute": 722, "uogonek": 611, "Edieresis": 667, "Dcroat": 722, "commaaccent": 250, "copyright": 737, "Emacron": 667, "ccaron": 556, "aring": 556, "Ncommaaccent": 722, "lacute": 278, "agrave": 556, "Tcommaaccent": 611, "Cacute": 722, "atilde": 556, "Edotaccent": 667, "scaron": 556, "scedilla": 556, "iacute": 278, "lozenge": 494, "Rcaron": 722, "Gcommaaccent": 778, "ucircumflex": 611, "acircumflex": 556, "Amacron": 722, "rcaron": 389, "ccedilla": 556, "Zdotaccent": 611, "Thorn": 667, "Omacron": 778, "Racute": 722, "Sacute": 667, "dcaron": 743, "Umacron": 722, "uring": 611, "threesuperior": 333, "Ograve": 778, "Agrave": 722, "Abreve": 722, "multiply": 584, "uacute": 611, "Tcaron": 611, "partialdiff": 494, "ydieresis": 556, "Nacute": 722, "icircumflex": 278, "Ecircumflex": 667, "adieresis": 556, "edieresis": 556, "cacute": 556, "nacute": 611, "umacron": 611, "Ncaron": 722, "Iacute": 278, "plusminus": 584, "brokenbar": 280, "registered": 737, "Gbreve": 778, "Idotaccent": 278, "summation": 600, "Egrave": 667, "racute": 389, "omacron": 611, "Zacute": 611, "Zcaron": 611, "greaterequal": 549, "Eth": 722, "Ccedilla": 722, "lcommaaccent": 278, "tcaron": 389, "eogonek": 556, "Uogonek": 722, "Aacute": 722, "Adieresis": 722, "egrave": 556, "zacute": 500, "iogonek": 278, "Oacute": 778, "oacute": 611, "amacron": 556, "sacute": 556, "idieresis": 278, "Ocircumflex": 778, "Ugrave": 722, "Delta": 612, "thorn": 611, "twosuperior": 333, "Odieresis": 778, "mu": 611, "igrave": 278, "ohungarumlaut": 611, "Eogonek": 667, "dcroat": 611, "threequarters": 834, "Scedilla": 667, "lcaron": 400, "Kcommaaccent": 722, "Lacute": 611, "trademark": 1000, "edotaccent": 556, "Igrave": 278, "Imacron": 278, "Lcaron": 611, "onehalf": 834, "lessequal": 549, "ocircumflex": 611, "ntilde": 611, "Uhungarumlaut": 722, "Eacute": 667, "emacron": 556, "gbreve": 611, "onequarter": 834, "Scaron": 667, "Scommaaccent": 667, "Ohungarumlaut": 778, "degree": 400, "ograve": 611, "Ccaron": 722, "ugrave": 611, "radical": 549, "Dcaron": 722, "rcommaaccent": 389, "Ntilde": 722, "otilde": 611, "Rcommaaccent": 722, "Lcommaaccent": 611, "Atilde": 722, "Aogonek": 722, "Aring": 722, "Otilde": 778, "zdotaccent": 500, "Ecaron": 667, "Iogonek": 278, "kcommaaccent": 556, "minus": 584, "Icircumflex": 278, "ncaron": 611, "tcommaaccent": 333, "logicalnot": 584, "odieresis": 611, "udieresis": 611, "notequal": 549, "gcommaaccent": 611, "eth": 611, "zcaron": 500, "ncommaaccent": 611, "onesuperior": 333, "imacron": 278, "Euro": 556}, + }, + "Helvetica-Oblique": { + types.NewRectangle(-170.0, -225.0, 1116.0, 931.0), + map[string]int{"space": 278, "exclam": 278, "quotedbl": 355, "numbersign": 556, "dollar": 556, "percent": 889, "ampersand": 667, "quoteright": 222, "parenleft": 333, "parenright": 333, "asterisk": 389, "plus": 584, "comma": 278, "hyphen": 333, "period": 278, "slash": 278, "zero": 556, "one": 556, "two": 556, "three": 556, "four": 556, "five": 556, "six": 556, "seven": 556, "eight": 556, "nine": 556, "colon": 278, "semicolon": 278, "less": 584, "equal": 584, "greater": 584, "question": 556, "at": 1015, "A": 667, "B": 667, "C": 722, "D": 722, "E": 667, "F": 611, "G": 778, "H": 722, "I": 278, "J": 500, "K": 667, "L": 556, "M": 833, "N": 722, "O": 778, "P": 667, "Q": 778, "R": 722, "S": 667, "T": 611, "U": 722, "V": 667, "W": 944, "X": 667, "Y": 667, "Z": 611, "bracketleft": 278, "backslash": 278, "bracketright": 278, "asciicircum": 469, "underscore": 556, "quoteleft": 222, "a": 556, "b": 556, "c": 500, "d": 556, "e": 556, "f": 278, "g": 556, "h": 556, "i": 222, "j": 222, "k": 500, "l": 222, "m": 833, "n": 556, "o": 556, "p": 556, "q": 556, "r": 333, "s": 500, "t": 278, "u": 556, "v": 500, "w": 722, "x": 500, "y": 500, "z": 500, "braceleft": 334, "bar": 260, "braceright": 334, "asciitilde": 584, "exclamdown": 333, "cent": 556, "sterling": 556, "fraction": 167, "yen": 556, "florin": 556, "section": 556, "currency": 556, "quotesingle": 191, "quotedblleft": 333, "guillemotleft": 556, "guilsinglleft": 333, "guilsinglright": 333, "fi": 500, "fl": 500, "endash": 556, "dagger": 556, "daggerdbl": 556, "periodcentered": 278, "paragraph": 537, "bullet": 350, "quotesinglbase": 222, "quotedblbase": 333, "quotedblright": 333, "guillemotright": 556, "ellipsis": 1000, "perthousand": 1000, "questiondown": 611, "grave": 333, "acute": 333, "circumflex": 333, "tilde": 333, "macron": 333, "breve": 333, "dotaccent": 333, "dieresis": 333, "ring": 333, "cedilla": 333, "hungarumlaut": 333, "ogonek": 333, "caron": 333, "emdash": 1000, "AE": 1000, "ordfeminine": 370, "Lslash": 556, "Oslash": 778, "OE": 1000, "ordmasculine": 365, "ae": 889, "dotlessi": 278, "lslash": 222, "oslash": 611, "oe": 944, "germandbls": 611, "Idieresis": 278, "eacute": 556, "abreve": 556, "uhungarumlaut": 556, "ecaron": 556, "Ydieresis": 667, "divide": 584, "Yacute": 667, "Acircumflex": 667, "aacute": 556, "Ucircumflex": 722, "yacute": 500, "scommaaccent": 500, "ecircumflex": 556, "Uring": 722, "Udieresis": 722, "aogonek": 556, "Uacute": 722, "uogonek": 556, "Edieresis": 667, "Dcroat": 722, "commaaccent": 250, "copyright": 737, "Emacron": 667, "ccaron": 500, "aring": 556, "Ncommaaccent": 722, "lacute": 222, "agrave": 556, "Tcommaaccent": 611, "Cacute": 722, "atilde": 556, "Edotaccent": 667, "scaron": 500, "scedilla": 500, "iacute": 278, "lozenge": 471, "Rcaron": 722, "Gcommaaccent": 778, "ucircumflex": 556, "acircumflex": 556, "Amacron": 667, "rcaron": 333, "ccedilla": 500, "Zdotaccent": 611, "Thorn": 667, "Omacron": 778, "Racute": 722, "Sacute": 667, "dcaron": 643, "Umacron": 722, "uring": 556, "threesuperior": 333, "Ograve": 778, "Agrave": 667, "Abreve": 667, "multiply": 584, "uacute": 556, "Tcaron": 611, "partialdiff": 476, "ydieresis": 500, "Nacute": 722, "icircumflex": 278, "Ecircumflex": 667, "adieresis": 556, "edieresis": 556, "cacute": 500, "nacute": 556, "umacron": 556, "Ncaron": 722, "Iacute": 278, "plusminus": 584, "brokenbar": 260, "registered": 737, "Gbreve": 778, "Idotaccent": 278, "summation": 600, "Egrave": 667, "racute": 333, "omacron": 556, "Zacute": 611, "Zcaron": 611, "greaterequal": 549, "Eth": 722, "Ccedilla": 722, "lcommaaccent": 222, "tcaron": 317, "eogonek": 556, "Uogonek": 722, "Aacute": 667, "Adieresis": 667, "egrave": 556, "zacute": 500, "iogonek": 222, "Oacute": 778, "oacute": 556, "amacron": 556, "sacute": 500, "idieresis": 278, "Ocircumflex": 778, "Ugrave": 722, "Delta": 612, "thorn": 556, "twosuperior": 333, "Odieresis": 778, "mu": 556, "igrave": 278, "ohungarumlaut": 556, "Eogonek": 667, "dcroat": 556, "threequarters": 834, "Scedilla": 667, "lcaron": 299, "Kcommaaccent": 667, "Lacute": 556, "trademark": 1000, "edotaccent": 556, "Igrave": 278, "Imacron": 278, "Lcaron": 556, "onehalf": 834, "lessequal": 549, "ocircumflex": 556, "ntilde": 556, "Uhungarumlaut": 722, "Eacute": 667, "emacron": 556, "gbreve": 556, "onequarter": 834, "Scaron": 667, "Scommaaccent": 667, "Ohungarumlaut": 778, "degree": 400, "ograve": 556, "Ccaron": 722, "ugrave": 556, "radical": 453, "Dcaron": 722, "rcommaaccent": 333, "Ntilde": 722, "otilde": 556, "Rcommaaccent": 722, "Lcommaaccent": 556, "Atilde": 667, "Aogonek": 667, "Aring": 667, "Otilde": 778, "zdotaccent": 500, "Ecaron": 667, "Iogonek": 278, "kcommaaccent": 500, "minus": 584, "Icircumflex": 278, "ncaron": 556, "tcommaaccent": 278, "logicalnot": 584, "odieresis": 556, "udieresis": 556, "notequal": 549, "gcommaaccent": 556, "eth": 556, "zcaron": 500, "ncommaaccent": 556, "onesuperior": 333, "imacron": 278, "Euro": 556}, + }, + "Helvetica": { + types.NewRectangle(-166.0, -225.0, 1000.0, 931.0), + map[string]int{"space": 278, "exclam": 278, "quotedbl": 355, "numbersign": 556, "dollar": 556, "percent": 889, "ampersand": 667, "quoteright": 222, "parenleft": 333, "parenright": 333, "asterisk": 389, "plus": 584, "comma": 278, "hyphen": 333, "period": 278, "slash": 278, "zero": 556, "one": 556, "two": 556, "three": 556, "four": 556, "five": 556, "six": 556, "seven": 556, "eight": 556, "nine": 556, "colon": 278, "semicolon": 278, "less": 584, "equal": 584, "greater": 584, "question": 556, "at": 1015, "A": 667, "B": 667, "C": 722, "D": 722, "E": 667, "F": 611, "G": 778, "H": 722, "I": 278, "J": 500, "K": 667, "L": 556, "M": 833, "N": 722, "O": 778, "P": 667, "Q": 778, "R": 722, "S": 667, "T": 611, "U": 722, "V": 667, "W": 944, "X": 667, "Y": 667, "Z": 611, "bracketleft": 278, "backslash": 278, "bracketright": 278, "asciicircum": 469, "underscore": 556, "quoteleft": 222, "a": 556, "b": 556, "c": 500, "d": 556, "e": 556, "f": 278, "g": 556, "h": 556, "i": 222, "j": 222, "k": 500, "l": 222, "m": 833, "n": 556, "o": 556, "p": 556, "q": 556, "r": 333, "s": 500, "t": 278, "u": 556, "v": 500, "w": 722, "x": 500, "y": 500, "z": 500, "braceleft": 334, "bar": 260, "braceright": 334, "asciitilde": 584, "exclamdown": 333, "cent": 556, "sterling": 556, "fraction": 167, "yen": 556, "florin": 556, "section": 556, "currency": 556, "quotesingle": 191, "quotedblleft": 333, "guillemotleft": 556, "guilsinglleft": 333, "guilsinglright": 333, "fi": 500, "fl": 500, "endash": 556, "dagger": 556, "daggerdbl": 556, "periodcentered": 278, "paragraph": 537, "bullet": 350, "quotesinglbase": 222, "quotedblbase": 333, "quotedblright": 333, "guillemotright": 556, "ellipsis": 1000, "perthousand": 1000, "questiondown": 611, "grave": 333, "acute": 333, "circumflex": 333, "tilde": 333, "macron": 333, "breve": 333, "dotaccent": 333, "dieresis": 333, "ring": 333, "cedilla": 333, "hungarumlaut": 333, "ogonek": 333, "caron": 333, "emdash": 1000, "AE": 1000, "ordfeminine": 370, "Lslash": 556, "Oslash": 778, "OE": 1000, "ordmasculine": 365, "ae": 889, "dotlessi": 278, "lslash": 222, "oslash": 611, "oe": 944, "germandbls": 611, "Idieresis": 278, "eacute": 556, "abreve": 556, "uhungarumlaut": 556, "ecaron": 556, "Ydieresis": 667, "divide": 584, "Yacute": 667, "Acircumflex": 667, "aacute": 556, "Ucircumflex": 722, "yacute": 500, "scommaaccent": 500, "ecircumflex": 556, "Uring": 722, "Udieresis": 722, "aogonek": 556, "Uacute": 722, "uogonek": 556, "Edieresis": 667, "Dcroat": 722, "commaaccent": 250, "copyright": 737, "Emacron": 667, "ccaron": 500, "aring": 556, "Ncommaaccent": 722, "lacute": 222, "agrave": 556, "Tcommaaccent": 611, "Cacute": 722, "atilde": 556, "Edotaccent": 667, "scaron": 500, "scedilla": 500, "iacute": 278, "lozenge": 471, "Rcaron": 722, "Gcommaaccent": 778, "ucircumflex": 556, "acircumflex": 556, "Amacron": 667, "rcaron": 333, "ccedilla": 500, "Zdotaccent": 611, "Thorn": 667, "Omacron": 778, "Racute": 722, "Sacute": 667, "dcaron": 643, "Umacron": 722, "uring": 556, "threesuperior": 333, "Ograve": 778, "Agrave": 667, "Abreve": 667, "multiply": 584, "uacute": 556, "Tcaron": 611, "partialdiff": 476, "ydieresis": 500, "Nacute": 722, "icircumflex": 278, "Ecircumflex": 667, "adieresis": 556, "edieresis": 556, "cacute": 500, "nacute": 556, "umacron": 556, "Ncaron": 722, "Iacute": 278, "plusminus": 584, "brokenbar": 260, "registered": 737, "Gbreve": 778, "Idotaccent": 278, "summation": 600, "Egrave": 667, "racute": 333, "omacron": 556, "Zacute": 611, "Zcaron": 611, "greaterequal": 549, "Eth": 722, "Ccedilla": 722, "lcommaaccent": 222, "tcaron": 317, "eogonek": 556, "Uogonek": 722, "Aacute": 667, "Adieresis": 667, "egrave": 556, "zacute": 500, "iogonek": 222, "Oacute": 778, "oacute": 556, "amacron": 556, "sacute": 500, "idieresis": 278, "Ocircumflex": 778, "Ugrave": 722, "Delta": 612, "thorn": 556, "twosuperior": 333, "Odieresis": 778, "mu": 556, "igrave": 278, "ohungarumlaut": 556, "Eogonek": 667, "dcroat": 556, "threequarters": 834, "Scedilla": 667, "lcaron": 299, "Kcommaaccent": 667, "Lacute": 556, "trademark": 1000, "edotaccent": 556, "Igrave": 278, "Imacron": 278, "Lcaron": 556, "onehalf": 834, "lessequal": 549, "ocircumflex": 556, "ntilde": 556, "Uhungarumlaut": 722, "Eacute": 667, "emacron": 556, "gbreve": 556, "onequarter": 834, "Scaron": 667, "Scommaaccent": 667, "Ohungarumlaut": 778, "degree": 400, "ograve": 556, "Ccaron": 722, "ugrave": 556, "radical": 453, "Dcaron": 722, "rcommaaccent": 333, "Ntilde": 722, "otilde": 556, "Rcommaaccent": 722, "Lcommaaccent": 556, "Atilde": 667, "Aogonek": 667, "Aring": 667, "Otilde": 778, "zdotaccent": 500, "Ecaron": 667, "Iogonek": 278, "kcommaaccent": 500, "minus": 584, "Icircumflex": 278, "ncaron": 556, "tcommaaccent": 278, "logicalnot": 584, "odieresis": 556, "udieresis": 556, "notequal": 549, "gcommaaccent": 556, "eth": 556, "zcaron": 500, "ncommaaccent": 556, "onesuperior": 333, "imacron": 278, "Euro": 556}, + }, + "Symbol": { + types.NewRectangle(-180.0, -293.0, 1090.0, 1010.0), + map[string]int{"space": 250, "exclam": 333, "universal": 713, "numbersign": 500, "existential": 549, "percent": 833, "ampersand": 778, "suchthat": 439, "parenleft": 333, "parenright": 333, "asteriskmath": 500, "plus": 549, "comma": 250, "minus": 549, "period": 250, "slash": 278, "zero": 500, "one": 500, "two": 500, "three": 500, "four": 500, "five": 500, "six": 500, "seven": 500, "eight": 500, "nine": 500, "colon": 278, "semicolon": 278, "less": 549, "equal": 549, "greater": 549, "question": 444, "congruent": 549, "Alpha": 722, "Beta": 667, "Chi": 722, "Delta": 612, "Epsilon": 611, "Phi": 763, "Gamma": 603, "Eta": 722, "Iota": 333, "theta1": 631, "Kappa": 722, "Lambda": 686, "Mu": 889, "Nu": 722, "Omicron": 722, "Pi": 768, "Theta": 741, "Rho": 556, "Sigma": 592, "Tau": 611, "Upsilon": 690, "sigma1": 439, "Omega": 768, "Xi": 645, "Psi": 795, "Zeta": 611, "bracketleft": 333, "therefore": 863, "bracketright": 333, "perpendicular": 658, "underscore": 500, "radicalex": 500, "alpha": 631, "beta": 549, "chi": 549, "delta": 494, "epsilon": 439, "phi": 521, "gamma": 411, "eta": 603, "iota": 329, "phi1": 603, "kappa": 549, "lambda": 549, "mu": 576, "nu": 521, "omicron": 549, "pi": 549, "theta": 521, "rho": 549, "sigma": 603, "tau": 439, "upsilon": 576, "omega1": 713, "omega": 686, "xi": 493, "psi": 686, "zeta": 494, "braceleft": 480, "bar": 200, "braceright": 480, "similar": 549, "Euro": 750, "Upsilon1": 620, "minute": 247, "lessequal": 549, "fraction": 167, "infinity": 713, "florin": 500, "club": 753, "diamond": 753, "heart": 753, "spade": 753, "arrowboth": 1042, "arrowleft": 987, "arrowup": 603, "arrowright": 987, "arrowdown": 603, "degree": 400, "plusminus": 549, "second": 411, "greaterequal": 549, "multiply": 549, "proportional": 713, "partialdiff": 494, "bullet": 460, "divide": 549, "notequal": 549, "equivalence": 549, "approxequal": 549, "ellipsis": 1000, "arrowvertex": 603, "arrowhorizex": 1000, "carriagereturn": 658, "aleph": 823, "Ifraktur": 686, "Rfraktur": 795, "weierstrass": 987, "circlemultiply": 768, "circleplus": 768, "emptyset": 823, "intersection": 768, "union": 768, "propersuperset": 713, "reflexsuperset": 713, "notsubset": 713, "propersubset": 713, "reflexsubset": 713, "element": 713, "notelement": 713, "angle": 768, "gradient": 713, "registerserif": 790, "copyrightserif": 790, "trademarkserif": 890, "product": 823, "radical": 549, "dotmath": 250, "logicalnot": 713, "logicaland": 603, "logicalor": 603, "arrowdblboth": 1042, "arrowdblleft": 987, "arrowdblup": 603, "arrowdblright": 987, "arrowdbldown": 603, "lozenge": 494, "angleleft": 329, "registersans": 790, "copyrightsans": 790, "trademarksans": 786, "summation": 713, "parenlefttp": 384, "parenleftex": 384, "parenleftbt": 384, "bracketlefttp": 384, "bracketleftex": 384, "bracketleftbt": 384, "bracelefttp": 494, "braceleftmid": 494, "braceleftbt": 494, "braceex": 494, "angleright": 329, "integral": 274, "integraltp": 686, "integralex": 686, "integralbt": 686, "parenrighttp": 384, "parenrightex": 384, "parenrightbt": 384, "bracketrighttp": 384, "bracketrightex": 384, "bracketrightbt": 384, "bracerighttp": 494, "bracerightmid": 494, "bracerightbt": 494, "apple": 790}, + }, + "Times-Bold": { + types.NewRectangle(-168.0, -218.0, 1000.0, 935.0), + map[string]int{"space": 250, "exclam": 333, "quotedbl": 555, "numbersign": 500, "dollar": 500, "percent": 1000, "ampersand": 833, "quoteright": 333, "parenleft": 333, "parenright": 333, "asterisk": 500, "plus": 570, "comma": 250, "hyphen": 333, "period": 250, "slash": 278, "zero": 500, "one": 500, "two": 500, "three": 500, "four": 500, "five": 500, "six": 500, "seven": 500, "eight": 500, "nine": 500, "colon": 333, "semicolon": 333, "less": 570, "equal": 570, "greater": 570, "question": 500, "at": 930, "A": 722, "B": 667, "C": 722, "D": 722, "E": 667, "F": 611, "G": 778, "H": 778, "I": 389, "J": 500, "K": 778, "L": 667, "M": 944, "N": 722, "O": 778, "P": 611, "Q": 778, "R": 722, "S": 556, "T": 667, "U": 722, "V": 722, "W": 1000, "X": 722, "Y": 722, "Z": 667, "bracketleft": 333, "backslash": 278, "bracketright": 333, "asciicircum": 581, "underscore": 500, "quoteleft": 333, "a": 500, "b": 556, "c": 444, "d": 556, "e": 444, "f": 333, "g": 500, "h": 556, "i": 278, "j": 333, "k": 556, "l": 278, "m": 833, "n": 556, "o": 500, "p": 556, "q": 556, "r": 444, "s": 389, "t": 333, "u": 556, "v": 500, "w": 722, "x": 500, "y": 500, "z": 444, "braceleft": 394, "bar": 220, "braceright": 394, "asciitilde": 520, "exclamdown": 333, "cent": 500, "sterling": 500, "fraction": 167, "yen": 500, "florin": 500, "section": 500, "currency": 500, "quotesingle": 278, "quotedblleft": 500, "guillemotleft": 500, "guilsinglleft": 333, "guilsinglright": 333, "fi": 556, "fl": 556, "endash": 500, "dagger": 500, "daggerdbl": 500, "periodcentered": 250, "paragraph": 540, "bullet": 350, "quotesinglbase": 333, "quotedblbase": 500, "quotedblright": 500, "guillemotright": 500, "ellipsis": 1000, "perthousand": 1000, "questiondown": 500, "grave": 333, "acute": 333, "circumflex": 333, "tilde": 333, "macron": 333, "breve": 333, "dotaccent": 333, "dieresis": 333, "ring": 333, "cedilla": 333, "hungarumlaut": 333, "ogonek": 333, "caron": 333, "emdash": 1000, "AE": 1000, "ordfeminine": 300, "Lslash": 667, "Oslash": 778, "OE": 1000, "ordmasculine": 330, "ae": 722, "dotlessi": 278, "lslash": 278, "oslash": 500, "oe": 722, "germandbls": 556, "Idieresis": 389, "eacute": 444, "abreve": 500, "uhungarumlaut": 556, "ecaron": 444, "Ydieresis": 722, "divide": 570, "Yacute": 722, "Acircumflex": 722, "aacute": 500, "Ucircumflex": 722, "yacute": 500, "scommaaccent": 389, "ecircumflex": 444, "Uring": 722, "Udieresis": 722, "aogonek": 500, "Uacute": 722, "uogonek": 556, "Edieresis": 667, "Dcroat": 722, "commaaccent": 250, "copyright": 747, "Emacron": 667, "ccaron": 444, "aring": 500, "Ncommaaccent": 722, "lacute": 278, "agrave": 500, "Tcommaaccent": 667, "Cacute": 722, "atilde": 500, "Edotaccent": 667, "scaron": 389, "scedilla": 389, "iacute": 278, "lozenge": 494, "Rcaron": 722, "Gcommaaccent": 778, "ucircumflex": 556, "acircumflex": 500, "Amacron": 722, "rcaron": 444, "ccedilla": 444, "Zdotaccent": 667, "Thorn": 611, "Omacron": 778, "Racute": 722, "Sacute": 556, "dcaron": 672, "Umacron": 722, "uring": 556, "threesuperior": 300, "Ograve": 778, "Agrave": 722, "Abreve": 722, "multiply": 570, "uacute": 556, "Tcaron": 667, "partialdiff": 494, "ydieresis": 500, "Nacute": 722, "icircumflex": 278, "Ecircumflex": 667, "adieresis": 500, "edieresis": 444, "cacute": 444, "nacute": 556, "umacron": 556, "Ncaron": 722, "Iacute": 389, "plusminus": 570, "brokenbar": 220, "registered": 747, "Gbreve": 778, "Idotaccent": 389, "summation": 600, "Egrave": 667, "racute": 444, "omacron": 500, "Zacute": 667, "Zcaron": 667, "greaterequal": 549, "Eth": 722, "Ccedilla": 722, "lcommaaccent": 278, "tcaron": 416, "eogonek": 444, "Uogonek": 722, "Aacute": 722, "Adieresis": 722, "egrave": 444, "zacute": 444, "iogonek": 278, "Oacute": 778, "oacute": 500, "amacron": 500, "sacute": 389, "idieresis": 278, "Ocircumflex": 778, "Ugrave": 722, "Delta": 612, "thorn": 556, "twosuperior": 300, "Odieresis": 778, "mu": 556, "igrave": 278, "ohungarumlaut": 500, "Eogonek": 667, "dcroat": 556, "threequarters": 750, "Scedilla": 556, "lcaron": 394, "Kcommaaccent": 778, "Lacute": 667, "trademark": 1000, "edotaccent": 444, "Igrave": 389, "Imacron": 389, "Lcaron": 667, "onehalf": 750, "lessequal": 549, "ocircumflex": 500, "ntilde": 556, "Uhungarumlaut": 722, "Eacute": 667, "emacron": 444, "gbreve": 500, "onequarter": 750, "Scaron": 556, "Scommaaccent": 556, "Ohungarumlaut": 778, "degree": 400, "ograve": 500, "Ccaron": 722, "ugrave": 556, "radical": 549, "Dcaron": 722, "rcommaaccent": 444, "Ntilde": 722, "otilde": 500, "Rcommaaccent": 722, "Lcommaaccent": 667, "Atilde": 722, "Aogonek": 722, "Aring": 722, "Otilde": 778, "zdotaccent": 444, "Ecaron": 667, "Iogonek": 389, "kcommaaccent": 556, "minus": 570, "Icircumflex": 389, "ncaron": 556, "tcommaaccent": 333, "logicalnot": 570, "odieresis": 500, "udieresis": 556, "notequal": 549, "gcommaaccent": 500, "eth": 500, "zcaron": 444, "ncommaaccent": 556, "onesuperior": 300, "imacron": 278, "Euro": 500}, + }, + "Times-BoldItalic": { + types.NewRectangle(-200.0, -218.0, 996.0, 921.0), + map[string]int{"space": 250, "exclam": 389, "quotedbl": 555, "numbersign": 500, "dollar": 500, "percent": 833, "ampersand": 778, "quoteright": 333, "parenleft": 333, "parenright": 333, "asterisk": 500, "plus": 570, "comma": 250, "hyphen": 333, "period": 250, "slash": 278, "zero": 500, "one": 500, "two": 500, "three": 500, "four": 500, "five": 500, "six": 500, "seven": 500, "eight": 500, "nine": 500, "colon": 333, "semicolon": 333, "less": 570, "equal": 570, "greater": 570, "question": 500, "at": 832, "A": 667, "B": 667, "C": 667, "D": 722, "E": 667, "F": 667, "G": 722, "H": 778, "I": 389, "J": 500, "K": 667, "L": 611, "M": 889, "N": 722, "O": 722, "P": 611, "Q": 722, "R": 667, "S": 556, "T": 611, "U": 722, "V": 667, "W": 889, "X": 667, "Y": 611, "Z": 611, "bracketleft": 333, "backslash": 278, "bracketright": 333, "asciicircum": 570, "underscore": 500, "quoteleft": 333, "a": 500, "b": 500, "c": 444, "d": 500, "e": 444, "f": 333, "g": 500, "h": 556, "i": 278, "j": 278, "k": 500, "l": 278, "m": 778, "n": 556, "o": 500, "p": 500, "q": 500, "r": 389, "s": 389, "t": 278, "u": 556, "v": 444, "w": 667, "x": 500, "y": 444, "z": 389, "braceleft": 348, "bar": 220, "braceright": 348, "asciitilde": 570, "exclamdown": 389, "cent": 500, "sterling": 500, "fraction": 167, "yen": 500, "florin": 500, "section": 500, "currency": 500, "quotesingle": 278, "quotedblleft": 500, "guillemotleft": 500, "guilsinglleft": 333, "guilsinglright": 333, "fi": 556, "fl": 556, "endash": 500, "dagger": 500, "daggerdbl": 500, "periodcentered": 250, "paragraph": 500, "bullet": 350, "quotesinglbase": 333, "quotedblbase": 500, "quotedblright": 500, "guillemotright": 500, "ellipsis": 1000, "perthousand": 1000, "questiondown": 500, "grave": 333, "acute": 333, "circumflex": 333, "tilde": 333, "macron": 333, "breve": 333, "dotaccent": 333, "dieresis": 333, "ring": 333, "cedilla": 333, "hungarumlaut": 333, "ogonek": 333, "caron": 333, "emdash": 1000, "AE": 944, "ordfeminine": 266, "Lslash": 611, "Oslash": 722, "OE": 944, "ordmasculine": 300, "ae": 722, "dotlessi": 278, "lslash": 278, "oslash": 500, "oe": 722, "germandbls": 500, "Idieresis": 389, "eacute": 444, "abreve": 500, "uhungarumlaut": 556, "ecaron": 444, "Ydieresis": 611, "divide": 570, "Yacute": 611, "Acircumflex": 667, "aacute": 500, "Ucircumflex": 722, "yacute": 444, "scommaaccent": 389, "ecircumflex": 444, "Uring": 722, "Udieresis": 722, "aogonek": 500, "Uacute": 722, "uogonek": 556, "Edieresis": 667, "Dcroat": 722, "commaaccent": 250, "copyright": 747, "Emacron": 667, "ccaron": 444, "aring": 500, "Ncommaaccent": 722, "lacute": 278, "agrave": 500, "Tcommaaccent": 611, "Cacute": 667, "atilde": 500, "Edotaccent": 667, "scaron": 389, "scedilla": 389, "iacute": 278, "lozenge": 494, "Rcaron": 667, "Gcommaaccent": 722, "ucircumflex": 556, "acircumflex": 500, "Amacron": 667, "rcaron": 389, "ccedilla": 444, "Zdotaccent": 611, "Thorn": 611, "Omacron": 722, "Racute": 667, "Sacute": 556, "dcaron": 608, "Umacron": 722, "uring": 556, "threesuperior": 300, "Ograve": 722, "Agrave": 667, "Abreve": 667, "multiply": 570, "uacute": 556, "Tcaron": 611, "partialdiff": 494, "ydieresis": 444, "Nacute": 722, "icircumflex": 278, "Ecircumflex": 667, "adieresis": 500, "edieresis": 444, "cacute": 444, "nacute": 556, "umacron": 556, "Ncaron": 722, "Iacute": 389, "plusminus": 570, "brokenbar": 220, "registered": 747, "Gbreve": 722, "Idotaccent": 389, "summation": 600, "Egrave": 667, "racute": 389, "omacron": 500, "Zacute": 611, "Zcaron": 611, "greaterequal": 549, "Eth": 722, "Ccedilla": 667, "lcommaaccent": 278, "tcaron": 366, "eogonek": 444, "Uogonek": 722, "Aacute": 667, "Adieresis": 667, "egrave": 444, "zacute": 389, "iogonek": 278, "Oacute": 722, "oacute": 500, "amacron": 500, "sacute": 389, "idieresis": 278, "Ocircumflex": 722, "Ugrave": 722, "Delta": 612, "thorn": 500, "twosuperior": 300, "Odieresis": 722, "mu": 576, "igrave": 278, "ohungarumlaut": 500, "Eogonek": 667, "dcroat": 500, "threequarters": 750, "Scedilla": 556, "lcaron": 382, "Kcommaaccent": 667, "Lacute": 611, "trademark": 1000, "edotaccent": 444, "Igrave": 389, "Imacron": 389, "Lcaron": 611, "onehalf": 750, "lessequal": 549, "ocircumflex": 500, "ntilde": 556, "Uhungarumlaut": 722, "Eacute": 667, "emacron": 444, "gbreve": 500, "onequarter": 750, "Scaron": 556, "Scommaaccent": 556, "Ohungarumlaut": 722, "degree": 400, "ograve": 500, "Ccaron": 667, "ugrave": 556, "radical": 549, "Dcaron": 722, "rcommaaccent": 389, "Ntilde": 722, "otilde": 500, "Rcommaaccent": 667, "Lcommaaccent": 611, "Atilde": 667, "Aogonek": 667, "Aring": 667, "Otilde": 722, "zdotaccent": 389, "Ecaron": 667, "Iogonek": 389, "kcommaaccent": 500, "minus": 606, "Icircumflex": 389, "ncaron": 556, "tcommaaccent": 278, "logicalnot": 606, "odieresis": 500, "udieresis": 556, "notequal": 549, "gcommaaccent": 500, "eth": 500, "zcaron": 389, "ncommaaccent": 556, "onesuperior": 300, "imacron": 278, "Euro": 500}, + }, + "Times-Italic": { + types.NewRectangle(-169.0, -217.0, 1010.0, 883.0), + map[string]int{"space": 250, "exclam": 333, "quotedbl": 420, "numbersign": 500, "dollar": 500, "percent": 833, "ampersand": 778, "quoteright": 333, "parenleft": 333, "parenright": 333, "asterisk": 500, "plus": 675, "comma": 250, "hyphen": 333, "period": 250, "slash": 278, "zero": 500, "one": 500, "two": 500, "three": 500, "four": 500, "five": 500, "six": 500, "seven": 500, "eight": 500, "nine": 500, "colon": 333, "semicolon": 333, "less": 675, "equal": 675, "greater": 675, "question": 500, "at": 920, "A": 611, "B": 611, "C": 667, "D": 722, "E": 611, "F": 611, "G": 722, "H": 722, "I": 333, "J": 444, "K": 667, "L": 556, "M": 833, "N": 667, "O": 722, "P": 611, "Q": 722, "R": 611, "S": 500, "T": 556, "U": 722, "V": 611, "W": 833, "X": 611, "Y": 556, "Z": 556, "bracketleft": 389, "backslash": 278, "bracketright": 389, "asciicircum": 422, "underscore": 500, "quoteleft": 333, "a": 500, "b": 500, "c": 444, "d": 500, "e": 444, "f": 278, "g": 500, "h": 500, "i": 278, "j": 278, "k": 444, "l": 278, "m": 722, "n": 500, "o": 500, "p": 500, "q": 500, "r": 389, "s": 389, "t": 278, "u": 500, "v": 444, "w": 667, "x": 444, "y": 444, "z": 389, "braceleft": 400, "bar": 275, "braceright": 400, "asciitilde": 541, "exclamdown": 389, "cent": 500, "sterling": 500, "fraction": 167, "yen": 500, "florin": 500, "section": 500, "currency": 500, "quotesingle": 214, "quotedblleft": 556, "guillemotleft": 500, "guilsinglleft": 333, "guilsinglright": 333, "fi": 500, "fl": 500, "endash": 500, "dagger": 500, "daggerdbl": 500, "periodcentered": 250, "paragraph": 523, "bullet": 350, "quotesinglbase": 333, "quotedblbase": 556, "quotedblright": 556, "guillemotright": 500, "ellipsis": 889, "perthousand": 1000, "questiondown": 500, "grave": 333, "acute": 333, "circumflex": 333, "tilde": 333, "macron": 333, "breve": 333, "dotaccent": 333, "dieresis": 333, "ring": 333, "cedilla": 333, "hungarumlaut": 333, "ogonek": 333, "caron": 333, "emdash": 889, "AE": 889, "ordfeminine": 276, "Lslash": 556, "Oslash": 722, "OE": 944, "ordmasculine": 310, "ae": 667, "dotlessi": 278, "lslash": 278, "oslash": 500, "oe": 667, "germandbls": 500, "Idieresis": 333, "eacute": 444, "abreve": 500, "uhungarumlaut": 500, "ecaron": 444, "Ydieresis": 556, "divide": 675, "Yacute": 556, "Acircumflex": 611, "aacute": 500, "Ucircumflex": 722, "yacute": 444, "scommaaccent": 389, "ecircumflex": 444, "Uring": 722, "Udieresis": 722, "aogonek": 500, "Uacute": 722, "uogonek": 500, "Edieresis": 611, "Dcroat": 722, "commaaccent": 250, "copyright": 760, "Emacron": 611, "ccaron": 444, "aring": 500, "Ncommaaccent": 667, "lacute": 278, "agrave": 500, "Tcommaaccent": 556, "Cacute": 667, "atilde": 500, "Edotaccent": 611, "scaron": 389, "scedilla": 389, "iacute": 278, "lozenge": 471, "Rcaron": 611, "Gcommaaccent": 722, "ucircumflex": 500, "acircumflex": 500, "Amacron": 611, "rcaron": 389, "ccedilla": 444, "Zdotaccent": 556, "Thorn": 611, "Omacron": 722, "Racute": 611, "Sacute": 500, "dcaron": 544, "Umacron": 722, "uring": 500, "threesuperior": 300, "Ograve": 722, "Agrave": 611, "Abreve": 611, "multiply": 675, "uacute": 500, "Tcaron": 556, "partialdiff": 476, "ydieresis": 444, "Nacute": 667, "icircumflex": 278, "Ecircumflex": 611, "adieresis": 500, "edieresis": 444, "cacute": 444, "nacute": 500, "umacron": 500, "Ncaron": 667, "Iacute": 333, "plusminus": 675, "brokenbar": 275, "registered": 760, "Gbreve": 722, "Idotaccent": 333, "summation": 600, "Egrave": 611, "racute": 389, "omacron": 500, "Zacute": 556, "Zcaron": 556, "greaterequal": 549, "Eth": 722, "Ccedilla": 667, "lcommaaccent": 278, "tcaron": 300, "eogonek": 444, "Uogonek": 722, "Aacute": 611, "Adieresis": 611, "egrave": 444, "zacute": 389, "iogonek": 278, "Oacute": 722, "oacute": 500, "amacron": 500, "sacute": 389, "idieresis": 278, "Ocircumflex": 722, "Ugrave": 722, "Delta": 612, "thorn": 500, "twosuperior": 300, "Odieresis": 722, "mu": 500, "igrave": 278, "ohungarumlaut": 500, "Eogonek": 611, "dcroat": 500, "threequarters": 750, "Scedilla": 500, "lcaron": 300, "Kcommaaccent": 667, "Lacute": 556, "trademark": 980, "edotaccent": 444, "Igrave": 333, "Imacron": 333, "Lcaron": 611, "onehalf": 750, "lessequal": 549, "ocircumflex": 500, "ntilde": 500, "Uhungarumlaut": 722, "Eacute": 611, "emacron": 444, "gbreve": 500, "onequarter": 750, "Scaron": 500, "Scommaaccent": 500, "Ohungarumlaut": 722, "degree": 400, "ograve": 500, "Ccaron": 667, "ugrave": 500, "radical": 453, "Dcaron": 722, "rcommaaccent": 389, "Ntilde": 667, "otilde": 500, "Rcommaaccent": 611, "Lcommaaccent": 556, "Atilde": 611, "Aogonek": 611, "Aring": 611, "Otilde": 722, "zdotaccent": 389, "Ecaron": 611, "Iogonek": 333, "kcommaaccent": 444, "minus": 675, "Icircumflex": 333, "ncaron": 500, "tcommaaccent": 278, "logicalnot": 675, "odieresis": 500, "udieresis": 500, "notequal": 549, "gcommaaccent": 500, "eth": 500, "zcaron": 389, "ncommaaccent": 500, "onesuperior": 300, "imacron": 278, "Euro": 500}, + }, + "Times-Roman": { + types.NewRectangle(-168.0, -218.0, 1000.0, 898.0), + map[string]int{"space": 250, "exclam": 333, "quotedbl": 408, "numbersign": 500, "dollar": 500, "percent": 833, "ampersand": 778, "quoteright": 333, "parenleft": 333, "parenright": 333, "asterisk": 500, "plus": 564, "comma": 250, "hyphen": 333, "period": 250, "slash": 278, "zero": 500, "one": 500, "two": 500, "three": 500, "four": 500, "five": 500, "six": 500, "seven": 500, "eight": 500, "nine": 500, "colon": 278, "semicolon": 278, "less": 564, "equal": 564, "greater": 564, "question": 444, "at": 921, "A": 722, "B": 667, "C": 667, "D": 722, "E": 611, "F": 556, "G": 722, "H": 722, "I": 333, "J": 389, "K": 722, "L": 611, "M": 889, "N": 722, "O": 722, "P": 556, "Q": 722, "R": 667, "S": 556, "T": 611, "U": 722, "V": 722, "W": 944, "X": 722, "Y": 722, "Z": 611, "bracketleft": 333, "backslash": 278, "bracketright": 333, "asciicircum": 469, "underscore": 500, "quoteleft": 333, "a": 444, "b": 500, "c": 444, "d": 500, "e": 444, "f": 333, "g": 500, "h": 500, "i": 278, "j": 278, "k": 500, "l": 278, "m": 778, "n": 500, "o": 500, "p": 500, "q": 500, "r": 333, "s": 389, "t": 278, "u": 500, "v": 500, "w": 722, "x": 500, "y": 500, "z": 444, "braceleft": 480, "bar": 200, "braceright": 480, "asciitilde": 541, "exclamdown": 333, "cent": 500, "sterling": 500, "fraction": 167, "yen": 500, "florin": 500, "section": 500, "currency": 500, "quotesingle": 180, "quotedblleft": 444, "guillemotleft": 500, "guilsinglleft": 333, "guilsinglright": 333, "fi": 556, "fl": 556, "endash": 500, "dagger": 500, "daggerdbl": 500, "periodcentered": 250, "paragraph": 453, "bullet": 350, "quotesinglbase": 333, "quotedblbase": 444, "quotedblright": 444, "guillemotright": 500, "ellipsis": 1000, "perthousand": 1000, "questiondown": 444, "grave": 333, "acute": 333, "circumflex": 333, "tilde": 333, "macron": 333, "breve": 333, "dotaccent": 333, "dieresis": 333, "ring": 333, "cedilla": 333, "hungarumlaut": 333, "ogonek": 333, "caron": 333, "emdash": 1000, "AE": 889, "ordfeminine": 276, "Lslash": 611, "Oslash": 722, "OE": 889, "ordmasculine": 310, "ae": 667, "dotlessi": 278, "lslash": 278, "oslash": 500, "oe": 722, "germandbls": 500, "Idieresis": 333, "eacute": 444, "abreve": 444, "uhungarumlaut": 500, "ecaron": 444, "Ydieresis": 722, "divide": 564, "Yacute": 722, "Acircumflex": 722, "aacute": 444, "Ucircumflex": 722, "yacute": 500, "scommaaccent": 389, "ecircumflex": 444, "Uring": 722, "Udieresis": 722, "aogonek": 444, "Uacute": 722, "uogonek": 500, "Edieresis": 611, "Dcroat": 722, "commaaccent": 250, "copyright": 760, "Emacron": 611, "ccaron": 444, "aring": 444, "Ncommaaccent": 722, "lacute": 278, "agrave": 444, "Tcommaaccent": 611, "Cacute": 667, "atilde": 444, "Edotaccent": 611, "scaron": 389, "scedilla": 389, "iacute": 278, "lozenge": 471, "Rcaron": 667, "Gcommaaccent": 722, "ucircumflex": 500, "acircumflex": 444, "Amacron": 722, "rcaron": 333, "ccedilla": 444, "Zdotaccent": 611, "Thorn": 556, "Omacron": 722, "Racute": 667, "Sacute": 556, "dcaron": 588, "Umacron": 722, "uring": 500, "threesuperior": 300, "Ograve": 722, "Agrave": 722, "Abreve": 722, "multiply": 564, "uacute": 500, "Tcaron": 611, "partialdiff": 476, "ydieresis": 500, "Nacute": 722, "icircumflex": 278, "Ecircumflex": 611, "adieresis": 444, "edieresis": 444, "cacute": 444, "nacute": 500, "umacron": 500, "Ncaron": 722, "Iacute": 333, "plusminus": 564, "brokenbar": 200, "registered": 760, "Gbreve": 722, "Idotaccent": 333, "summation": 600, "Egrave": 611, "racute": 333, "omacron": 500, "Zacute": 611, "Zcaron": 611, "greaterequal": 549, "Eth": 722, "Ccedilla": 667, "lcommaaccent": 278, "tcaron": 326, "eogonek": 444, "Uogonek": 722, "Aacute": 722, "Adieresis": 722, "egrave": 444, "zacute": 444, "iogonek": 278, "Oacute": 722, "oacute": 500, "amacron": 444, "sacute": 389, "idieresis": 278, "Ocircumflex": 722, "Ugrave": 722, "Delta": 612, "thorn": 500, "twosuperior": 300, "Odieresis": 722, "mu": 500, "igrave": 278, "ohungarumlaut": 500, "Eogonek": 611, "dcroat": 500, "threequarters": 750, "Scedilla": 556, "lcaron": 344, "Kcommaaccent": 722, "Lacute": 611, "trademark": 980, "edotaccent": 444, "Igrave": 333, "Imacron": 333, "Lcaron": 611, "onehalf": 750, "lessequal": 549, "ocircumflex": 500, "ntilde": 500, "Uhungarumlaut": 722, "Eacute": 611, "emacron": 444, "gbreve": 500, "onequarter": 750, "Scaron": 556, "Scommaaccent": 556, "Ohungarumlaut": 722, "degree": 400, "ograve": 500, "Ccaron": 667, "ugrave": 500, "radical": 453, "Dcaron": 722, "rcommaaccent": 333, "Ntilde": 722, "otilde": 500, "Rcommaaccent": 667, "Lcommaaccent": 611, "Atilde": 722, "Aogonek": 722, "Aring": 722, "Otilde": 722, "zdotaccent": 444, "Ecaron": 611, "Iogonek": 333, "kcommaaccent": 500, "minus": 564, "Icircumflex": 333, "ncaron": 500, "tcommaaccent": 278, "logicalnot": 564, "odieresis": 500, "udieresis": 500, "notequal": 549, "gcommaaccent": 500, "eth": 500, "zcaron": 444, "ncommaaccent": 500, "onesuperior": 300, "imacron": 278, "Euro": 500}, + }, + "ZapfDingbats": { + types.NewRectangle(-1.0, -143.0, 981.0, 820.0), + map[string]int{"space": 278, "a1": 974, "a2": 961, "a202": 974, "a3": 980, "a4": 719, "a5": 789, "a119": 790, "a118": 791, "a117": 690, "a11": 960, "a12": 939, "a13": 549, "a14": 855, "a15": 911, "a16": 933, "a105": 911, "a17": 945, "a18": 974, "a19": 755, "a20": 846, "a21": 762, "a22": 761, "a23": 571, "a24": 677, "a25": 763, "a26": 760, "a27": 759, "a28": 754, "a6": 494, "a7": 552, "a8": 537, "a9": 577, "a10": 692, "a29": 786, "a30": 788, "a31": 788, "a32": 790, "a33": 793, "a34": 794, "a35": 816, "a36": 823, "a37": 789, "a38": 841, "a39": 823, "a40": 833, "a41": 816, "a42": 831, "a43": 923, "a44": 744, "a45": 723, "a46": 749, "a47": 790, "a48": 792, "a49": 695, "a50": 776, "a51": 768, "a52": 792, "a53": 759, "a54": 707, "a55": 708, "a56": 682, "a57": 701, "a58": 826, "a59": 815, "a60": 789, "a61": 789, "a62": 707, "a63": 687, "a64": 696, "a65": 689, "a66": 786, "a67": 787, "a68": 713, "a69": 791, "a70": 785, "a71": 791, "a72": 873, "a73": 761, "a74": 762, "a203": 762, "a75": 759, "a204": 759, "a76": 892, "a77": 892, "a78": 788, "a79": 784, "a81": 438, "a82": 138, "a83": 277, "a84": 415, "a97": 392, "a98": 392, "a99": 668, "a100": 668, "a89": 390, "a90": 390, "a93": 317, "a94": 317, "a91": 276, "a92": 276, "a205": 509, "a85": 509, "a206": 410, "a86": 410, "a87": 234, "a88": 234, "a95": 334, "a96": 334, "a101": 732, "a102": 544, "a103": 544, "a104": 910, "a106": 667, "a107": 760, "a108": 760, "a112": 776, "a111": 595, "a110": 694, "a109": 626, "a120": 788, "a121": 788, "a122": 788, "a123": 788, "a124": 788, "a125": 788, "a126": 788, "a127": 788, "a128": 788, "a129": 788, "a130": 788, "a131": 788, "a132": 788, "a133": 788, "a134": 788, "a135": 788, "a136": 788, "a137": 788, "a138": 788, "a139": 788, "a140": 788, "a141": 788, "a142": 788, "a143": 788, "a144": 788, "a145": 788, "a146": 788, "a147": 788, "a148": 788, "a149": 788, "a150": 788, "a151": 788, "a152": 788, "a153": 788, "a154": 788, "a155": 788, "a156": 788, "a157": 788, "a158": 788, "a159": 788, "a160": 894, "a161": 838, "a163": 1016, "a164": 458, "a196": 748, "a165": 924, "a192": 748, "a166": 918, "a167": 927, "a168": 928, "a169": 928, "a170": 834, "a171": 873, "a172": 828, "a173": 924, "a162": 924, "a174": 917, "a175": 930, "a176": 931, "a177": 463, "a178": 883, "a179": 836, "a193": 836, "a180": 867, "a199": 867, "a181": 696, "a200": 696, "a182": 874, "a201": 874, "a183": 760, "a184": 946, "a197": 771, "a185": 865, "a194": 771, "a198": 888, "a186": 967, "a195": 888, "a187": 831, "a188": 873, "a189": 927, "a190": 970, "a191": 918}, + }, +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/api.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/api.go new file mode 100644 index 0000000..dc83c6b --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/api.go @@ -0,0 +1,169 @@ +/* + Copyright 2018 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Package api lets you integrate pdfcpu's operations into your Go backend. +// +// There are two api layers supporting all pdfcpu operations: +// 1) The file based layer (used by pdfcpu's cli) +// 2) The io.ReadSeeker/io.Writer based layer for backend integration. +// +// For any pdfcpu command there are two functions. +// +// The file based function always calls the io.ReadSeeker/io.Writer based function: +// func CommandFile(inFile, outFile string, conf *pdf.Configuration) error +// func Command(rs io.ReadSeeker, w io.Writer, conf *pdf.Configuration) error +// +// eg. for optimization: +// func OptimizeFile(inFile, outFile string, conf *pdf.Configuration) error +// func Optimize(rs io.ReadSeeker, w io.Writer, conf *pdf.Configuration) error +package api + +import ( + "bufio" + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate" +) + +// ReadContext uses an io.ReadSeeker to build an internal structure holding its cross reference table aka the Context. +func ReadContext(rs io.ReadSeeker, conf *pdfcpu.Configuration) (*pdfcpu.Context, error) { + return pdfcpu.Read(rs, conf) +} + +// ReadContextFile returns inFile's validated context. +func ReadContextFile(inFile string) (*pdfcpu.Context, error) { + f, err := os.Open(inFile) + if err != nil { + return nil, err + } + defer f.Close() + ctx, err := ReadContext(f, pdfcpu.NewDefaultConfiguration()) + if err != nil { + return nil, err + } + if err = validate.XRefTable(ctx.XRefTable); err != nil { + return nil, err + } + return ctx, err +} + +// ValidateContext validates a PDF context. +func ValidateContext(ctx *pdfcpu.Context) error { + return validate.XRefTable(ctx.XRefTable) +} + +// OptimizeContext optimizes a PDF context. +func OptimizeContext(ctx *pdfcpu.Context) error { + return pdfcpu.OptimizeXRefTable(ctx) +} + +// WriteContext writes a PDF context to w. +func WriteContext(ctx *pdfcpu.Context, w io.Writer) error { + if f, ok := w.(*os.File); ok { + ctx.Write.Fp = f + } + ctx.Write.Writer = bufio.NewWriter(w) + return pdfcpu.Write(ctx) +} + +// WriteContextFile writes a PDF context to outFile. +func WriteContextFile(ctx *pdfcpu.Context, outFile string) error { + f, err := os.Create(outFile) + if err != nil { + return err + } + defer f.Close() + return WriteContext(ctx, f) +} + +func readAndValidate(rs io.ReadSeeker, conf *pdfcpu.Configuration, from1 time.Time) (ctx *pdfcpu.Context, dur1, dur2 float64, err error) { + if ctx, err = ReadContext(rs, conf); err != nil { + return nil, 0, 0, err + } + + dur1 = time.Since(from1).Seconds() + + if conf.ValidationMode == pdfcpu.ValidationNone { + // Bypass validation + return ctx, 0, 0, nil + } + + from2 := time.Now() + + if err = validate.XRefTable(ctx.XRefTable); err != nil { + return nil, 0, 0, err + } + + dur2 = time.Since(from2).Seconds() + + return ctx, dur1, dur2, nil +} + +func readValidateAndOptimize(rs io.ReadSeeker, conf *pdfcpu.Configuration, from1 time.Time) (ctx *pdfcpu.Context, dur1, dur2, dur3 float64, err error) { + ctx, dur1, dur2, err = readAndValidate(rs, conf, from1) + if err != nil { + return nil, 0, 0, 0, err + } + + from3 := time.Now() + + if err = OptimizeContext(ctx); err != nil { + return nil, 0, 0, 0, err + } + + dur3 = time.Since(from3).Seconds() + + return ctx, dur1, dur2, dur3, nil +} + +func logOperationStats(ctx *pdfcpu.Context, op string, durRead, durVal, durOpt, durWrite, durTotal float64) { + log.Stats.Printf("XRefTable:\n%s\n", ctx) + pdfcpu.TimingStats(op, durRead, durVal, durOpt, durWrite, durTotal) + if ctx.Read.FileSize > 0 { + ctx.Read.LogStats(ctx.Optimized) + ctx.Write.LogStats() + } +} + +// EnsureDefaultConfigAt switches to the pdfcpu config dir located at path. +// If path/pdfcpu is not existent, it will be created including config.yml +func EnsureDefaultConfigAt(path string) error { + // Call if you have specific requirements regarding the location of the pdfcpu config dir. + return pdfcpu.EnsureDefaultConfigAt(path) +} + +// DisableConfigDir disables the configuration directory. +// Any needed default configuration will be loaded from configuration.go +// Since the config dir also contains the user font dir, this also limits font usage to the default core font set +// No user fonts will be available. +func DisableConfigDir() { + // Call if you don't want to use a specific configuration + // and also do not need to use user fonts. + pdfcpu.ConfigPath = "disable" +} + +// LoadConfiguration locates and loads the default configuration +// and also loads installed user fonts. +func LoadConfiguration() { + // Call if you don't have a specific config dir location + // and need to use user fonts for stamping or watermarking. + pdfcpu.NewDefaultConfiguration() +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/attach.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/attach.go new file mode 100644 index 0000000..79d4cac --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/attach.go @@ -0,0 +1,331 @@ +/* + Copyright 2019 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// ListAttachments returns a list of embedded file attachments of rs. +func ListAttachments(rs io.ReadSeeker, conf *pdfcpu.Configuration) ([]string, error) { + if rs == nil { + return nil, errors.New("pdfcpu: ListAttachments: Please provide rs") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return nil, err + } + + fromWrite := time.Now() + + aa, err := ctx.ListAttachments() + if err != nil { + return nil, err + } + + var ss []string + for _, a := range aa { + s := a.FileName + if a.Desc != "" { + s = fmt.Sprintf("%s (%s)", s, a.Desc) + } + ss = append(ss, s) + } + sort.Strings(ss) + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + log.Stats.Printf("XRefTable:\n%s\n", ctx) + pdfcpu.TimingStats("list files", durRead, durVal, durOpt, durWrite, durTotal) + + return ss, nil +} + +// ListAttachmentsFile returns a list of embedded file attachments of inFile. +func ListAttachmentsFile(inFile string, conf *pdfcpu.Configuration) ([]string, error) { + f, err := os.Open(inFile) + if err != nil { + return nil, err + } + defer f.Close() + return ListAttachments(f, conf) +} + +// AddAttachments embeds files into a PDF context read from rs and writes the result to w. +// file is either a file name or a file name and a description separated by a comma. +func AddAttachments(rs io.ReadSeeker, w io.Writer, files []string, coll bool, conf *pdfcpu.Configuration) error { + if rs == nil { + return errors.New("pdfcpu: AddAttachments: Please provide rs") + } + if w == nil { + return errors.New("pdfcpu: AddAttachments: Please provide w") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + from := time.Now() + var ok bool + + for _, fn := range files { + s := strings.Split(fn, ",") + if len(s) == 0 || len(s) > 2 { + continue + } + + fileName := s[0] + desc := "" + if len(s) == 2 { + desc = s[1] + } + + log.CLI.Printf("adding %s\n", fileName) + f, err := os.Open(fileName) + if err != nil { + return err + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + return err + } + mt := fi.ModTime() + + a := pdfcpu.Attachment{Reader: f, ID: filepath.Base(fileName), Desc: desc, ModTime: &mt} + if err = ctx.AddAttachment(a, coll); err != nil { + return err + } + ok = true + } + + if !ok { + return errors.New("no attachment added") + } + + durAdd := time.Since(from).Seconds() + fromWrite := time.Now() + + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := durAdd + time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "add attachment, write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// AddAttachmentsFile embeds files into a PDF context read from inFile and writes the result to outFile. +func AddAttachmentsFile(inFile, outFile string, files []string, coll bool, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + if outFile == "" || inFile == outFile { + os.Remove(tmpFile) + } + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return AddAttachments(f1, f2, files, coll, conf) +} + +// RemoveAttachments deletes embedded files from a PDF context read from rs and writes the result to w. +func RemoveAttachments(rs io.ReadSeeker, w io.Writer, files []string, conf *pdfcpu.Configuration) error { + if rs == nil { + return errors.New("pdfcpu: RemoveAttachments: Please provide rs") + } + if w == nil { + return errors.New("pdfcpu: RemoveAttachments: Please provide w") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + from := time.Now() + + var ok bool + if ok, err = ctx.RemoveAttachments(files); err != nil { + return err + } + if !ok { + return errors.New("no attachment removed") + } + + durRemove := time.Since(from).Seconds() + fromWrite := time.Now() + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := durRemove + time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "remove att, write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// RemoveAttachmentsFile deletes embedded files from a PDF context read from inFile and writes the result to outFile. +func RemoveAttachmentsFile(inFile, outFile string, files []string, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + if outFile == "" || inFile == outFile { + os.Remove(tmpFile) + } + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return RemoveAttachments(f1, f2, files, conf) +} + +// ExtractAttachments extracts embedded files from a PDF context read from rs into outDir. +func ExtractAttachments(rs io.ReadSeeker, outDir string, fileNames []string, conf *pdfcpu.Configuration) error { + if rs == nil { + return errors.New("pdfcpu: ExtractAttachments: Please provide rs") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + fromWrite := time.Now() + + aa, err := ctx.ExtractAttachments(fileNames) + if err != nil { + return err + } + + for _, a := range aa { + fileName := filepath.Join(outDir, a.FileName) + log.CLI.Printf("writing %s\n", fileName) + f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) + if err != nil { + return err + } + if _, err = io.Copy(f, a); err != nil { + return err + } + if err := f.Close(); err != nil { + return err + } + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + log.Stats.Printf("XRefTable:\n%s\n", ctx) + pdfcpu.TimingStats("write files", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// ExtractAttachmentsFile extracts embedded files from a PDF context read from inFile into outDir. +func ExtractAttachmentsFile(inFile, outDir string, files []string, conf *pdfcpu.Configuration) error { + f, err := os.Open(inFile) + if err != nil { + return err + } + defer f.Close() + return ExtractAttachments(f, outDir, files, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/boxes.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/boxes.go new file mode 100644 index 0000000..27c5686 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/boxes.go @@ -0,0 +1,325 @@ +/* +Copyright 2020 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// PageBoundariesFromBoxList parses a list of box types. +func PageBoundariesFromBoxList(s string) (*pdfcpu.PageBoundaries, error) { + return pdfcpu.ParseBoxList(s) +} + +// PageBoundaries parses a list of box definitions and assignments. +func PageBoundaries(s string, unit pdfcpu.DisplayUnit) (*pdfcpu.PageBoundaries, error) { + return pdfcpu.ParsePageBoundaries(s, unit) +} + +// Box parses a box definition. +func Box(s string, u pdfcpu.DisplayUnit) (*pdfcpu.Box, error) { + return pdfcpu.ParseBox(s, u) +} + +// ListBoxes returns a list of page boundaries for selected pages of rs. +func ListBoxes(rs io.ReadSeeker, selectedPages []string, pb *pdfcpu.PageBoundaries, conf *pdfcpu.Configuration) ([]string, error) { + if rs == nil { + return nil, errors.New("pdfcpu: ListBoxes: missing rs") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + conf.Cmd = pdfcpu.LISTBOXES + } + ctx, _, _, _, err := readValidateAndOptimize(rs, conf, time.Now()) + if err != nil { + return nil, err + } + if err := ctx.EnsurePageCount(); err != nil { + return nil, err + } + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return nil, err + } + + return ctx.ListPageBoundaries(pages, pb) +} + +// ListBoxesFile returns a list of page boundaries for selected pages of inFile. +func ListBoxesFile(inFile string, selectedPages []string, pb *pdfcpu.PageBoundaries, conf *pdfcpu.Configuration) ([]string, error) { + f, err := os.Open(inFile) + if err != nil { + return nil, err + } + defer f.Close() + + if pb == nil { + pb = &pdfcpu.PageBoundaries{} + pb.SelectAll() + } + log.CLI.Printf("listing %s for %s\n", pb, inFile) + return ListBoxes(f, selectedPages, pb, conf) +} + +// AddBoxes adds page boundaries for selected pages of rs and writes result to w. +func AddBoxes(rs io.ReadSeeker, w io.Writer, selectedPages []string, pb *pdfcpu.PageBoundaries, conf *pdfcpu.Configuration) error { + if rs == nil { + return errors.New("pdfcpu: AddBoxes: missing rs") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.ADDBOXES + + ctx, _, _, _, err := readValidateAndOptimize(rs, conf, time.Now()) + if err != nil { + return err + } + if err := ctx.EnsurePageCount(); err != nil { + return err + } + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return err + } + + if err = ctx.AddPageBoundaries(pages, pb); err != nil { + return err + } + + if conf.ValidationMode != pdfcpu.ValidationNone { + if err = ValidateContext(ctx); err != nil { + return err + } + } + + return WriteContext(ctx, w) +} + +// AddBoxesFile adds page boundaries for selected pages of inFile and writes result to outFile. +func AddBoxesFile(inFile, outFile string, selectedPages []string, pb *pdfcpu.PageBoundaries, conf *pdfcpu.Configuration) error { + log.CLI.Printf("adding %s for %s\n", pb, inFile) + var ( + f1, f2 *os.File + err error + ) + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return AddBoxes(f1, f2, selectedPages, pb, conf) +} + +// RemoveBoxes removes page boundaries as specified in pb for selected pages of rs and writes result to w. +func RemoveBoxes(rs io.ReadSeeker, w io.Writer, selectedPages []string, pb *pdfcpu.PageBoundaries, conf *pdfcpu.Configuration) error { + if rs == nil { + return errors.New("pdfcpu: RemoveBoxes: missing rs") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.REMOVEBOXES + + ctx, _, _, _, err := readValidateAndOptimize(rs, conf, time.Now()) + if err != nil { + return err + } + if err := ctx.EnsurePageCount(); err != nil { + return err + } + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return err + } + + if err = ctx.RemovePageBoundaries(pages, pb); err != nil { + return err + } + + if conf.ValidationMode != pdfcpu.ValidationNone { + if err = ValidateContext(ctx); err != nil { + return err + } + } + + return WriteContext(ctx, w) +} + +// RemoveBoxesFile removes page boundaries as specified in pb for selected pages of inFile and writes result to outFile. +func RemoveBoxesFile(inFile, outFile string, selectedPages []string, pb *pdfcpu.PageBoundaries, conf *pdfcpu.Configuration) error { + log.CLI.Printf("removing %s for %s\n", pb, inFile) + var ( + f1, f2 *os.File + err error + ) + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return RemoveBoxes(f1, f2, selectedPages, pb, conf) +} + +// Crop adds crop boxes for selected pages of rs and writes result to w. +func Crop(rs io.ReadSeeker, w io.Writer, selectedPages []string, b *pdfcpu.Box, conf *pdfcpu.Configuration) error { + if rs == nil { + return errors.New("pdfcpu: Crop: missing rs") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.CROP + + ctx, _, _, _, err := readValidateAndOptimize(rs, conf, time.Now()) + if err != nil { + return err + } + if err := ctx.EnsurePageCount(); err != nil { + return err + } + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return err + } + + if err = ctx.Crop(pages, b); err != nil { + return err + } + + if conf.ValidationMode != pdfcpu.ValidationNone { + if err = ValidateContext(ctx); err != nil { + return err + } + } + + return WriteContext(ctx, w) +} + +// CropFile adds crop boxes for selected pages of inFile and writes result to outFile. +func CropFile(inFile, outFile string, selectedPages []string, b *pdfcpu.Box, conf *pdfcpu.Configuration) error { + log.CLI.Printf("cropping %s\n", inFile) + var ( + f1, f2 *os.File + err error + ) + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return Crop(f1, f2, selectedPages, b, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/collect.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/collect.go new file mode 100644 index 0000000..f3cbc5e --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/collect.go @@ -0,0 +1,104 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" +) + +// Collect creates a custom PDF page sequence for selected pages of rs and writes the result to w. +func Collect(rs io.ReadSeeker, w io.Writer, selectedPages []string, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.COLLECT + + fromStart := time.Now() + ctx, _, _, _, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + pages, err := PagesForPageCollection(ctx.PageCount, selectedPages) + if err != nil { + return err + } + + ctxDest, err := ctx.ExtractPages(pages, true) + if err != nil { + return err + } + + if conf.ValidationMode != pdfcpu.ValidationNone { + if err = ValidateContext(ctxDest); err != nil { + return err + } + } + + return WriteContext(ctxDest, w) +} + +// CollectFile creates a custom PDF page sequence for inFile and writes the result to outFile. +func CollectFile(inFile, outFile string, selectedPages []string, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return Collect(f1, f2, selectedPages, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/create.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/create.go new file mode 100644 index 0000000..eee685b --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/create.go @@ -0,0 +1,34 @@ +/* + Copyright 2019 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "os" + + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" +) + +// CreatePDFFile creates a PDF file for an xRefTable and writes it to outFile. +func CreatePDFFile(xRefTable *pdf.XRefTable, outFile string, conf *pdf.Configuration) error { + f, err := os.Create(outFile) + if err != nil { + return err + } + defer f.Close() + ctx := pdf.CreateContext(xRefTable, conf) + return WriteContext(ctx, f) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/crypto.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/crypto.go new file mode 100644 index 0000000..74cc526 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/crypto.go @@ -0,0 +1,66 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// EncryptFile encrypts inFile and writes the result to outFile. +// A configuration containing the current passwords is required. +func EncryptFile(inFile, outFile string, conf *pdfcpu.Configuration) error { + if conf == nil { + return errors.New("pdfcpu: missing configuration for encryption") + } + conf.Cmd = pdfcpu.ENCRYPT + return OptimizeFile(inFile, outFile, conf) +} + +// DecryptFile decrypts inFile and writes the result to outFile. +// A configuration containing the current passwords is required. +func DecryptFile(inFile, outFile string, conf *pdfcpu.Configuration) error { + if conf == nil { + return errors.New("pdfcpu: missing configuration for decryption") + } + conf.Cmd = pdfcpu.DECRYPT + return OptimizeFile(inFile, outFile, conf) +} + +// ChangeUserPasswordFile reads inFile, changes the user password and writes the result to outFile. +// A configuration containing the current passwords is required. +func ChangeUserPasswordFile(inFile, outFile string, pwOld, pwNew string, conf *pdfcpu.Configuration) error { + if conf == nil { + return errors.New("pdfcpu: missing configuration for change user password") + } + conf.Cmd = pdfcpu.CHANGEUPW + conf.UserPW = pwOld + conf.UserPWNew = &pwNew + return OptimizeFile(inFile, outFile, conf) +} + +// ChangeOwnerPasswordFile reads inFile, changes the user password and writes the result to outFile. +// A configuration containing the current passwords is required. +func ChangeOwnerPasswordFile(inFile, outFile string, pwOld, pwNew string, conf *pdfcpu.Configuration) error { + if conf == nil { + return errors.New("pdfcpu: missing configuration for change owner password") + } + conf.Cmd = pdfcpu.CHANGEOPW + conf.OwnerPW = pwOld + conf.OwnerPWNew = &pwNew + return OptimizeFile(inFile, outFile, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/extract.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/extract.go new file mode 100644 index 0000000..b7fc255 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/extract.go @@ -0,0 +1,358 @@ +/* + Copyright 2019 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "fmt" + "io" + "os" + "path/filepath" + "strings" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// ExtractImages dumps embedded image resources from rs into outDir for selected pages. +func ExtractImages(rs io.ReadSeeker, outDir, fileName string, selectedPages []string, conf *pdfcpu.Configuration) error { + if rs == nil { + return errors.New("pdfcpu: ExtractImages: Please provide rs") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + fromWrite := time.Now() + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return err + } + + fileName = strings.TrimSuffix(filepath.Base(fileName), ".pdf") + + for i, v := range pages { + if !v { + continue + } + ii, err := ctx.ExtractPageImages(i) + if err != nil { + return err + } + for _, img := range ii { + outFile := filepath.Join(outDir, fmt.Sprintf("%s_%d_%s.%s", fileName, i, img.Name, img.Type)) + log.CLI.Printf("writing %s\n", outFile) + w, err := os.Create(outFile) + if err != nil { + return err + } + if _, err = io.Copy(w, img); err != nil { + return err + } + if err := w.Close(); err != nil { + return err + } + } + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + log.Stats.Printf("XRefTable:\n%s\n", ctx) + pdfcpu.TimingStats("write images", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// ExtractImagesFile dumps embedded image resources from inFile into outDir for selected pages. +func ExtractImagesFile(inFile, outDir string, selectedPages []string, conf *pdfcpu.Configuration) error { + f, err := os.Open(inFile) + if err != nil { + return err + } + defer f.Close() + log.CLI.Printf("extracting images from %s into %s/ ...\n", inFile, outDir) + return ExtractImages(f, outDir, filepath.Base(inFile), selectedPages, conf) +} + +// ExtractFonts dumps embedded fontfiles from rs into outDir for selected pages. +func ExtractFonts(rs io.ReadSeeker, outDir, fileName string, selectedPages []string, conf *pdfcpu.Configuration) error { + if rs == nil { + return errors.New("pdfcpu: ExtractFonts: Please provide rs") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + fromWrite := time.Now() + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return err + } + + fileName = strings.TrimSuffix(filepath.Base(fileName), ".pdf") + + for i, v := range pages { + if !v { + continue + } + ff, err := ctx.ExtractPageFonts(i) + if err != nil { + return err + } + for _, f := range ff { + outFile := filepath.Join(outDir, fmt.Sprintf("%s_%s.%s", fileName, f.Name, f.Type)) + log.CLI.Printf("writing %s\n", outFile) + w, err := os.Create(outFile) + if err != nil { + return err + } + if _, err = io.Copy(w, f); err != nil { + return err + } + if err := w.Close(); err != nil { + return err + } + } + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + log.Stats.Printf("XRefTable:\n%s\n", ctx) + pdfcpu.TimingStats("write fonts", durRead, durVal, durOpt, durWrite, durTotal) + return nil +} + +// ExtractFontsFile dumps embedded fontfiles from inFile into outDir for selected pages. +func ExtractFontsFile(inFile, outDir string, selectedPages []string, conf *pdfcpu.Configuration) error { + f, err := os.Open(inFile) + if err != nil { + return err + } + defer f.Close() + log.CLI.Printf("extracting fonts from %s into %s/ ...\n", inFile, outDir) + return ExtractFonts(f, outDir, filepath.Base(inFile), selectedPages, conf) +} + +// ExtractPages generates single page PDF files from rs in outDir for selected pages. +func ExtractPages(rs io.ReadSeeker, outDir, fileName string, selectedPages []string, conf *pdfcpu.Configuration) error { + if rs == nil { + return errors.New("pdfcpu: ExtractPages: Please provide rs") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + conf.Cmd = pdfcpu.EXTRACTPAGES + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + fromWrite := time.Now() + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return err + } + + fileName = strings.TrimSuffix(filepath.Base(fileName), ".pdf") + + for i, v := range pages { + if !v { + continue + } + ctxNew, err := ctx.ExtractPage(i) + if err != nil { + return err + } + outFile := filepath.Join(outDir, fmt.Sprintf("%s_page_%d.pdf", fileName, i)) + log.CLI.Printf("writing %s\n", outFile) + if err := WriteContextFile(ctxNew, outFile); err != nil { + return err + } + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + log.Stats.Printf("XRefTable:\n%s\n", ctx) + pdfcpu.TimingStats("write PDFs", durRead, durVal, durOpt, durWrite, durTotal) + return nil +} + +// ExtractPagesFile generates single page PDF files from inFile in outDir for selected pages. +func ExtractPagesFile(inFile, outDir string, selectedPages []string, conf *pdfcpu.Configuration) error { + f, err := os.Open(inFile) + if err != nil { + return err + } + defer f.Close() + log.CLI.Printf("extracting pages from %s into %s/ ...\n", inFile, outDir) + return ExtractPages(f, outDir, filepath.Base(inFile), selectedPages, conf) +} + +// ExtractContent dumps "PDF source" files from rs into outDir for selected pages. +func ExtractContent(rs io.ReadSeeker, outDir, fileName string, selectedPages []string, conf *pdfcpu.Configuration) error { + if rs == nil { + return errors.New("pdfcpu: ExtractContent: Please provide rs") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + fromWrite := time.Now() + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return err + } + + fileName = strings.TrimSuffix(filepath.Base(fileName), ".pdf") + + for p, v := range pages { + if !v { + continue + } + r, err := ctx.ExtractPageContent(p) + if err != nil { + return err + } + if r == nil { + continue + } + outFile := filepath.Join(outDir, fmt.Sprintf("%s_Content_page_%d.txt", fileName, p)) + log.CLI.Printf("writing %s\n", outFile) + f, err := os.Create(outFile) + if err != nil { + return err + } + if _, err = io.Copy(f, r); err != nil { + return err + } + if err := f.Close(); err != nil { + return err + } + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + log.Stats.Printf("XRefTable:\n%s\n", ctx) + pdfcpu.TimingStats("write content", durRead, durVal, durOpt, durWrite, durTotal) + return nil +} + +// ExtractContentFile dumps "PDF source" files from inFile into outDir for selected pages. +func ExtractContentFile(inFile, outDir string, selectedPages []string, conf *pdfcpu.Configuration) error { + f, err := os.Open(inFile) + if err != nil { + return err + } + defer f.Close() + log.CLI.Printf("extracting content from %s into %s/ ...\n", inFile, outDir) + return ExtractContent(f, outDir, inFile, selectedPages, conf) +} + +// ExtractMetadata dumps all metadata dict entries for rs into outDir. +func ExtractMetadata(rs io.ReadSeeker, outDir, fileName string, conf *pdfcpu.Configuration) error { + if rs == nil { + return errors.New("pdfcpu: ExtractMetadata: Please provide rs") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + fromWrite := time.Now() + + mm, err := ctx.ExtractMetadata() + if err != nil { + return err + } + + if len(mm) > 0 { + fileName = strings.TrimSuffix(filepath.Base(fileName), ".pdf") + for _, m := range mm { + outFile := filepath.Join(outDir, fmt.Sprintf("%s_Metadata_%s_%d_%d.txt", fileName, m.ParentType, m.ParentObjNr, m.ObjNr)) + log.CLI.Printf("writing %s\n", outFile) + f, err := os.Create(outFile) + if err != nil { + return err + } + if _, err = io.Copy(f, m); err != nil { + return err + } + if err := f.Close(); err != nil { + return err + } + } + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + log.Stats.Printf("XRefTable:\n%s\n", ctx) + pdfcpu.TimingStats("write metadata", durRead, durVal, durOpt, durWrite, durTotal) + return nil +} + +// ExtractMetadataFile dumps all metadata dict entries for inFile into outDir. +func ExtractMetadataFile(inFile, outDir string, conf *pdfcpu.Configuration) error { + f, err := os.Open(inFile) + if err != nil { + return err + } + defer f.Close() + log.CLI.Printf("extracting metadata from %s into %s/ ...\n", inFile, outDir) + return ExtractMetadata(f, outDir, filepath.Base(inFile), conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/fonts.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/fonts.go new file mode 100644 index 0000000..2059946 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/fonts.go @@ -0,0 +1,235 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "bytes" + "fmt" + "path/filepath" + "sort" + "strings" + "unicode/utf8" + + "github.com/pdfcpu/pdfcpu/pkg/font" + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func isSupportedFontFile(filename string) bool { + return strings.HasSuffix(strings.ToLower(filename), ".gob") +} + +// ListFonts returns a list of supported fonts. +func ListFonts() ([]string, error) { + + // Get list of PDF core fonts. + coreFonts := font.CoreFontNames() + for i, s := range coreFonts { + coreFonts[i] = " " + s + } + sort.Strings(coreFonts) + + sscf := []string{"Corefonts:"} + sscf = append(sscf, coreFonts...) + + // Get installed fonts from pdfcpu config dir in users home dir + userFonts := font.UserFontNamesVerbose() + for i, s := range userFonts { + userFonts[i] = " " + s + } + sort.Strings(userFonts) + + ssuf := []string{fmt.Sprintf("Userfonts(%s):", font.UserFontDir)} + ssuf = append(ssuf, userFonts...) + + sscf = append(sscf, "") + return append(sscf, ssuf...), nil +} + +// InstallFonts installs true type fonts for embedding. +func InstallFonts(fileNames []string) error { + log.CLI.Printf("installing to %s...", font.UserFontDir) + for _, fn := range fileNames { + switch filepath.Ext(fn) { + case ".ttf": + //log.CLI.Println(filepath.Base(fn)) + if err := font.InstallTrueTypeFont(font.UserFontDir, fn); err != nil { + log.CLI.Printf("%v", err) + } + case ".ttc": + //log.CLI.Println(filepath.Base(fn)) + if err := font.InstallTrueTypeCollection(font.UserFontDir, fn); err != nil { + log.CLI.Printf("%v", err) + } + } + } + return font.LoadUserFonts() +} + +func rowLabel(i int, td pdf.TextDescriptor, baseFontName, baseFontKey string, buf *bytes.Buffer, mb *pdf.Rectangle, left bool) { + x := 39. + if !left { + x = 7750 + } + s := fmt.Sprintf("#%02X", i) + td.X, td.Y, td.Text = x, float64(7677-i*30), s + td.StrokeCol, td.FillCol = pdf.Black, pdf.SimpleColor{B: .8} + td.FontName, td.FontKey, td.FontSize = baseFontName, baseFontKey, 14 + pdf.WriteMultiLine(buf, mb, nil, td) +} + +func columnsLabel(td pdf.TextDescriptor, baseFontName, baseFontKey string, buf *bytes.Buffer, mb *pdf.Rectangle, top bool) { + y := 7700. + if !top { + y = 0 + } + td.FontName, td.FontKey = baseFontName, baseFontKey + for i := 0; i < 256; i++ { + s := fmt.Sprintf("#%02X", i) + td.X, td.Y, td.Text, td.FontSize = float64(70+i*30), y, s, 14 + td.StrokeCol, td.FillCol = pdf.Black, pdf.SimpleColor{B: .8} + pdf.WriteMultiLine(buf, mb, nil, td) + } +} + +func surrogate(r rune) bool { + return r >= 0xD800 && r <= 0xDFFF +} +func writeUserFontDemoContent(p pdf.Page, fontName string, plane int) { + baseFontName := "Helvetica" + baseFontSize := 24 + baseFontKey := p.Fm.EnsureKey(baseFontName) + + fontKey := p.Fm.EnsureKey(fontName) + fontSize := 24 + + fillCol := pdf.NewSimpleColor(0xf7e6c7) + pdf.DrawGrid(p.Buf, 16*16, 16*16, pdf.RectForWidthAndHeight(55, 16, 16*480, 16*480), pdf.Black, &fillCol) + + td := pdf.TextDescriptor{ + FontName: fontName, + FontKey: fontKey, + FontSize: baseFontSize, + HAlign: pdf.AlignCenter, + VAlign: pdf.AlignBaseline, + Scale: 1.0, + ScaleAbs: true, + RMode: pdf.RMFill, + StrokeCol: pdf.Black, + FillCol: pdf.NewSimpleColor(0xab6f30), + ShowBackground: true, + BackgroundCol: pdf.SimpleColor{R: 1., G: .98, B: .77}, + } + + from := plane * 0x10000 + to := (plane+1)*0x10000 - 1 + s := fmt.Sprintf("%s %d points (%04X - %04X)", fontName, fontSize, from, to) + + td.X, td.Y, td.Text = p.MediaBox.Width()/2, 7750, s + td.FontName, td.FontKey = baseFontName, baseFontKey + td.StrokeCol, td.FillCol = pdf.NewSimpleColor(0x77bdbd), pdf.NewSimpleColor(0xab6f30) + pdf.WriteMultiLine(p.Buf, p.MediaBox, nil, td) + + columnsLabel(td, baseFontName, baseFontKey, p.Buf, p.MediaBox, true) + base := rune(plane * 0x10000) + for j := 0; j < 256; j++ { + rowLabel(j, td, baseFontName, baseFontKey, p.Buf, p.MediaBox, true) + buf := make([]byte, 4) + td.StrokeCol, td.FillCol = pdf.Black, pdf.Black + td.FontName, td.FontKey, td.FontSize = fontName, fontKey, fontSize-2 + for i := 0; i < 256; i++ { + r := base + rune(j*256+i) + s = " " + if !surrogate(r) { + n := utf8.EncodeRune(buf, r) + s = string(buf[:n]) + } + td.X, td.Y, td.Text = float64(70+i*30), float64(7672-j*30), s + pdf.WriteMultiLine(p.Buf, p.MediaBox, nil, td) + } + rowLabel(j, td, baseFontName, baseFontKey, p.Buf, p.MediaBox, false) + } + columnsLabel(td, baseFontName, baseFontKey, p.Buf, p.MediaBox, false) +} + +func createUserFontDemoPage(w, h, plane int, fontName string) pdf.Page { + mediaBox := pdf.RectForDim(float64(w), float64(h)) + p := pdf.NewPageWithBg(mediaBox, pdf.NewSimpleColor(0xbeded9)) + writeUserFontDemoContent(p, fontName, plane) + return p +} + +func planeString(i int) string { + switch i { + case 0: + return "BMP" // Basic Multilingual Plane + case 1: + return "SMP" // Supplementary Multilingual Plane + case 2: + return "SIP" // Supplementary Ideographic Plane + case 3: + return "TIP" // Tertiary Ideographic Plane + case 14: + return "SSP" // Supplementary Special-purpose Plane + case 15: + return "SPUA" // Supplementary Private Use Area Plane + } + return "" +} + +// CreateUserFontDemoFiles creates single page PDF for each Unicode plane covered. +func CreateUserFontDemoFiles(dir, fn string) error { + w, h := 7800, 7800 + ttf, ok := font.UserFontMetrics[fn] + if !ok { + return errors.Errorf("pdfcpu: font %s not available\n", fn) + } + // Create a single page PDF for each Unicode plane with existing glyphs. + for i := range ttf.Planes { + p := createUserFontDemoPage(w, h, i, fn) + xRefTable, err := pdfcpu.CreateDemoXRef(p) + if err != nil { + return err + } + fileName := filepath.Join(dir, fn+"_"+planeString(i)+".pdf") + if err := CreatePDFFile(xRefTable, fileName, nil); err != nil { + return err + } + } + return nil +} + +// CreateCheatSheetsUserFonts creates single page PDF cheat sheets for installed user fonts. +func CreateCheatSheetsUserFonts(fontNames []string) error { + if len(fontNames) == 0 { + fontNames = font.UserFontNames() + } + sort.Strings(fontNames) + for _, fn := range fontNames { + if !font.IsUserFont(fn) { + log.CLI.Printf("unknown user font: %s\n", fn) + continue + } + log.CLI.Println("creating cheatsheets for: " + fn) + if err := CreateUserFontDemoFiles(".", fn); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/importImage.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/importImage.go new file mode 100644 index 0000000..91ece80 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/importImage.go @@ -0,0 +1,170 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "bufio" + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" +) + +// Import parses an Import command string into an internal structure. +func Import(s string, u pdfcpu.DisplayUnit) (*pdfcpu.Import, error) { + return pdfcpu.ParseImportDetails(s, u) +} + +// ImportImages appends PDF pages containing images to rs and writes the result to w. +// If rs == nil a new PDF file will be written to w. +func ImportImages(rs io.ReadSeeker, w io.Writer, imgs []io.Reader, imp *pdfcpu.Import, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.IMPORTIMAGES + + if imp == nil { + imp = pdfcpu.DefaultImportConfig() + } + + var ( + ctx *pdfcpu.Context + err error + ) + + if rs != nil { + ctx, _, _, err = readAndValidate(rs, conf, time.Now()) + } else { + ctx, err = pdfcpu.CreateContextWithXRefTable(conf, imp.PageDim) + } + if err != nil { + return err + } + + pagesIndRef, err := ctx.Pages() + if err != nil { + return err + } + + // This is the page tree root. + pagesDict, err := ctx.DereferenceDict(*pagesIndRef) + if err != nil { + return err + } + + for _, r := range imgs { + + indRef, err := pdfcpu.NewPageForImage(ctx.XRefTable, r, pagesIndRef, imp) + if err != nil { + return err + } + + if err = pdfcpu.AppendPageTree(indRef, 1, pagesDict); err != nil { + return err + } + + ctx.PageCount++ + } + + if conf.ValidationMode != pdfcpu.ValidationNone { + if err = ValidateContext(ctx); err != nil { + return err + } + } + + if err = WriteContext(ctx, w); err != nil { + return err + } + + log.Stats.Printf("XRefTable:\n%s\n", ctx) + + return nil +} + +func fileExists(filename string) bool { + f, err := os.Open(filename) + defer f.Close() + return err == nil +} + +// ImportImagesFile appends PDF pages containing images to outFile which will be created if necessary. +func ImportImagesFile(imgFiles []string, outFile string, imp *pdfcpu.Import, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + rs := io.ReadSeeker(nil) + f1 = nil + tmpFile := outFile + if fileExists(outFile) { + if f1, err = os.Open(outFile); err != nil { + return err + } + rs = f1 + tmpFile += ".tmp" + log.CLI.Printf("appending to %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", outFile) + } + + rc := make([]io.ReadCloser, len(imgFiles)) + rr := make([]io.Reader, len(imgFiles)) + for i, fn := range imgFiles { + f, err := os.Open(fn) + if err != nil { + return err + } + rc[i] = f + rr[i] = bufio.NewReader(f) + } + + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + if f1 != nil { + f1.Close() + os.Remove(tmpFile) + } + for _, f := range rc { + f.Close() + } + return + } + if err = f2.Close(); err != nil { + return + } + if f1 != nil { + if err = f1.Close(); err != nil { + return + } + if err = os.Rename(tmpFile, outFile); err != nil { + return + } + } + for _, f := range rc { + if err := f.Close(); err != nil { + return + } + } + }() + + return ImportImages(rs, f2, rr, imp, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/info.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/info.go new file mode 100644 index 0000000..9571e05 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/info.go @@ -0,0 +1,60 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" +) + +// Info returns information about rs. +func Info(rs io.ReadSeeker, selectedPages []string, conf *pdfcpu.Configuration) ([]string, error) { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } else { + // Validation loads infodict. + conf.ValidationMode = pdfcpu.ValidationRelaxed + } + ctx, _, _, err := readAndValidate(rs, conf, time.Now()) + if err != nil { + return nil, err + } + if err := ctx.EnsurePageCount(); err != nil { + return nil, err + } + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, false) + if err != nil { + return nil, err + } + if err := ctx.DetectWatermarks(); err != nil { + return nil, err + } + return ctx.InfoDigest(pages) +} + +// InfoFile returns information about inFile. +func InfoFile(inFile string, selectedPages []string, conf *pdfcpu.Configuration) ([]string, error) { + f, err := os.Open(inFile) + if err != nil { + return nil, err + } + defer f.Close() + return Info(f, selectedPages, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/keywords.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/keywords.go new file mode 100644 index 0000000..563ceef --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/keywords.go @@ -0,0 +1,221 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// ListKeywords returns the keyword list of rs. +func ListKeywords(rs io.ReadSeeker, conf *pdf.Configuration) ([]string, error) { + if conf == nil { + conf = pdf.NewDefaultConfiguration() + } else { + // Validation loads infodict. + conf.ValidationMode = pdf.ValidationRelaxed + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return nil, err + } + + fromWrite := time.Now() + list, err := pdf.KeywordsList(ctx.XRefTable) + if err != nil { + return nil, err + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + log.Stats.Printf("XRefTable:\n%s\n", ctx) + pdf.TimingStats("list files", durRead, durVal, durOpt, durWrite, durTotal) + + return list, nil +} + +// ListKeywordsFile returns the keyword list of inFile. +func ListKeywordsFile(inFile string, conf *pdf.Configuration) ([]string, error) { + f, err := os.Open(inFile) + if err != nil { + return nil, err + } + defer f.Close() + return ListKeywords(f, conf) +} + +// AddKeywords embeds files into a PDF context read from rs and writes the result to w. +func AddKeywords(rs io.ReadSeeker, w io.Writer, files []string, conf *pdf.Configuration) error { + if conf == nil { + conf = pdf.NewDefaultConfiguration() + } else { + // Validation loads infodict. + conf.ValidationMode = pdf.ValidationRelaxed + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + from := time.Now() + + if err = pdf.KeywordsAdd(ctx.XRefTable, files); err != nil { + return err + } + + durAdd := time.Since(from).Seconds() + fromWrite := time.Now() + + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := durAdd + time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "add keyword, write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// AddKeywordsFile embeds files into a PDF context read from inFile and writes the result to outFile. +func AddKeywordsFile(inFile, outFile string, files []string, conf *pdf.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + if outFile == "" || inFile == outFile { + os.Remove(tmpFile) + } + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return AddKeywords(f1, f2, files, conf) +} + +// RemoveKeywords deletes embedded files from a PDF context read from rs and writes the result to w. +func RemoveKeywords(rs io.ReadSeeker, w io.Writer, keywords []string, conf *pdf.Configuration) error { + if conf == nil { + conf = pdf.NewDefaultConfiguration() + } else { + // Validation loads infodict. + conf.ValidationMode = pdf.ValidationRelaxed + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + from := time.Now() + + var ok bool + if ok, err = pdf.KeywordsRemove(ctx.XRefTable, keywords); err != nil { + return err + } + if !ok { + return errors.New("no keyword removed") + } + + durRemove := time.Since(from).Seconds() + fromWrite := time.Now() + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := durRemove + time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "remove att, write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// RemoveKeywordsFile deletes embedded files from a PDF context read from inFile and writes the result to outFile. +func RemoveKeywordsFile(inFile, outFile string, keywords []string, conf *pdf.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + if outFile == "" || inFile == outFile { + os.Remove(tmpFile) + } + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return RemoveKeywords(f1, f2, keywords, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/merge.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/merge.go new file mode 100644 index 0000000..57777c6 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/merge.go @@ -0,0 +1,198 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// appendTo appends inFile to ctxDest's page tree. +func appendTo(rs io.ReadSeeker, ctxDest *pdfcpu.Context) error { + ctxSource, _, _, err := readAndValidate(rs, ctxDest.Configuration, time.Now()) + if err != nil { + return err + } + + // Merge the source context into the dest context. + return pdfcpu.MergeXRefTables(ctxSource, ctxDest) +} + +// ReadSeekerCloser combines io.ReadSeeker and io.Closer +type ReadSeekerCloser interface { + io.ReadSeeker + io.Closer +} + +// Merge merges a sequence of PDF streams and writes the result to w. +func Merge(rsc []io.ReadSeeker, w io.Writer, conf *pdfcpu.Configuration) error { + if rsc == nil { + return errors.New("pdfcpu: Merge: Please provide rsc") + } + if w == nil { + return errors.New("pdfcpu: Merge: Please provide w") + } + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.MERGECREATE + + ctxDest, _, _, err := readAndValidate(rsc[0], conf, time.Now()) + if err != nil { + return err + } + + ctxDest.EnsureVersionForWriting() + + // Repeatedly merge files into fileDest's xref table. + for _, f := range rsc[1:] { + if err = appendTo(f, ctxDest); err != nil { + return err + } + } + + if err = OptimizeContext(ctxDest); err != nil { + return err + } + + if conf.ValidationMode != pdfcpu.ValidationNone { + if err = ValidateContext(ctxDest); err != nil { + return err + } + } + + return WriteContext(ctxDest, w) +} + +// MergeCreateFile merges a sequence of inFiles and writes the result to outFile. +// This operation corresponds to file concatenation in the order specified by inFiles. +// The first entry of inFiles serves as the destination context where all remaining files get merged into. +func MergeCreateFile(inFiles []string, outFile string, conf *pdfcpu.Configuration) error { + ff := []*os.File(nil) + for _, f := range inFiles { + log.CLI.Println(f) + f, err := os.Open(f) + if err != nil { + return err + } + ff = append(ff, f) + } + f, err := os.Create(outFile) + if err != nil { + return err + } + + defer func() { + if err != nil { + f.Close() + for _, f := range ff { + f.Close() + } + } + if err = f.Close(); err != nil { + return + } + for _, f := range ff { + if err = f.Close(); err != nil { + return + } + } + }() + + rs := make([]io.ReadSeeker, len(ff)) + for i, f := range ff { + rs[i] = f + } + + log.CLI.Printf("writing %s...\n", outFile) + return Merge(rs, f, conf) +} + +func prepareReadSeekers(ff []*os.File) []io.ReadSeeker { + rss := make([]io.ReadSeeker, len(ff)) + for i, f := range ff { + rss[i] = f + } + return rss +} + +// MergeAppendFile merges a sequence of inFiles and writes the result to outFile. +// This operation corresponds to file concatenation in the order specified by inFiles. +// If outFile already exists, inFiles will be appended. +func MergeAppendFile(inFiles []string, outFile string, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + tmpFile := outFile + if fileExists(outFile) { + if f1, err = os.Open(outFile); err != nil { + return err + } + tmpFile += ".tmp" + log.CLI.Printf("appending to %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", outFile) + } + + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + ff := []*os.File(nil) + if f1 != nil { + ff = append(ff, f1) + } + for _, f := range inFiles { + log.CLI.Println(f) + f, err := os.Open(f) + if err != nil { + return err + } + ff = append(ff, f) + } + + defer func() { + if err != nil { + f2.Close() + if f1 != nil { + os.Remove(tmpFile) + } + for _, f := range ff { + f.Close() + } + return + } + if err = f2.Close(); err != nil { + return + } + if f1 != nil { + if err = os.Rename(tmpFile, outFile); err != nil { + return + } + } + for _, f := range ff { + if err = f.Close(); err != nil { + return + } + } + }() + + return Merge(prepareReadSeekers(ff), f2, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/nup.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/nup.go new file mode 100644 index 0000000..8b9ef8f --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/nup.go @@ -0,0 +1,175 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" +) + +// PDFNUp returns an NUp configuration for Nup-ing PDF files. +func PDFNUp(val int, desc string) (*pdfcpu.NUp, error) { + return pdfcpu.PDFNUpConfig(val, desc) +} + +// ImageNUp returns an NUp configuration for Nup-ing image files. +func ImageNUp(val int, desc string) (*pdfcpu.NUp, error) { + return pdfcpu.ImageNUpConfig(val, desc) +} + +// PDFGrid returns a grid configuration for Nup-ing PDF files. +func PDFGrid(rows, cols int, desc string) (*pdfcpu.NUp, error) { + return pdfcpu.PDFGridConfig(rows, cols, desc) +} + +// ImageGrid returns a grid configuration for Nup-ing image files. +func ImageGrid(rows, cols int, desc string) (*pdfcpu.NUp, error) { + return pdfcpu.ImageGridConfig(rows, cols, desc) +} + +// NUpFromImage creates a single page n-up PDF for one image +// or a sequence of n-up pages for more than one image. +func NUpFromImage(conf *pdfcpu.Configuration, imageFileNames []string, nup *pdfcpu.NUp) (*pdfcpu.Context, error) { + if nup.PageDim == nil { + // Set default paper size. + nup.PageDim = pdfcpu.PaperSize[nup.PageSize] + } + + ctx, err := pdfcpu.CreateContextWithXRefTable(conf, nup.PageDim) + if err != nil { + return nil, err + } + + pagesIndRef, err := ctx.Pages() + if err != nil { + return nil, err + } + + // This is the page tree root. + pagesDict, err := ctx.DereferenceDict(*pagesIndRef) + if err != nil { + return nil, err + } + + if len(imageFileNames) == 1 { + err = pdfcpu.NUpFromOneImage(ctx, imageFileNames[0], nup, pagesDict, pagesIndRef) + } else { + err = pdfcpu.NUpFromMultipleImages(ctx, imageFileNames, nup, pagesDict, pagesIndRef) + } + + return ctx, err +} + +// NUp rearranges PDF pages or images into page grids and writes the result to w. +// Either rs or imgFiles will be used. +func NUp(rs io.ReadSeeker, w io.Writer, imgFiles, selectedPages []string, nup *pdfcpu.NUp, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.NUP + + log.Info.Printf("%s", nup) + + var ( + ctx *pdfcpu.Context + err error + ) + + if nup.ImgInputFile { + + if ctx, err = NUpFromImage(conf, imgFiles, nup); err != nil { + return err + } + + } else { + + if ctx, _, _, err = readAndValidate(rs, conf, time.Now()); err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return err + } + + // New pages get added to ctx while old pages get deleted. + // This way we avoid migrating objects between contexts. + if err = ctx.NUpFromPDF(pages, nup); err != nil { + return err + } + + } + + if conf.ValidationMode != pdfcpu.ValidationNone { + if err = ValidateContext(ctx); err != nil { + return err + } + } + + if err = WriteContext(ctx, w); err != nil { + return err + } + + log.Stats.Printf("XRefTable:\n%s\n", ctx) + + return nil +} + +// NUpFile rearranges PDF pages or images into page grids and writes the result to outFile. +func NUpFile(inFiles []string, outFile string, selectedPages []string, nup *pdfcpu.NUp, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + if !nup.ImgInputFile { + // Nup from a PDF page. + if f1, err = os.Open(inFiles[0]); err != nil { + return err + } + } + + if f2, err = os.Create(outFile); err != nil { + return err + } + log.CLI.Printf("writing %s...\n", outFile) + + defer func() { + if err != nil { + if f1 != nil { + f1.Close() + } + f2.Close() + return + } + if f1 != nil { + if err = f1.Close(); err != nil { + return + } + } + err = f2.Close() + return + + }() + + return NUp(f1, f2, inFiles, selectedPages, nup, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/optimize.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/optimize.go new file mode 100644 index 0000000..0c3e183 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/optimize.go @@ -0,0 +1,108 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// Optimize reads a PDF stream from rs and writes the optimized PDF stream to w. +func Optimize(rs io.ReadSeeker, w io.Writer, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + conf.Cmd = pdfcpu.OPTIMIZE + } + + fromStart := time.Now() + + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + log.Stats.Printf("XRefTable:\n%s\n", ctx) + fromWrite := time.Now() + + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "write", durRead, durVal, durOpt, durWrite, durTotal) + + // For Optimize only. + if ctx.StatsFileName != "" { + err = pdfcpu.AppendStatsFile(ctx) + if err != nil { + return errors.Wrap(err, "Write stats failed.") + } + } + + return nil +} + +// OptimizeFile reads inFile and writes the optimized PDF to outFile. +// If outFile is not provided then inFile gets overwritten +// which leads to the same result as when inFile equals outFile. +func OptimizeFile(inFile, outFile string, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return Optimize(f1, f2, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/pages.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/pages.go new file mode 100644 index 0000000..768a124 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/pages.go @@ -0,0 +1,253 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// InsertPages inserts a blank page before or after every page selected of rs and writes the result to w. +func InsertPages(rs io.ReadSeeker, w io.Writer, selectedPages []string, before bool, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.INSERTPAGESAFTER + if before { + conf.Cmd = pdfcpu.INSERTPAGESBEFORE + } + + fromStart := time.Now() + ctx, _, _, _, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return err + } + + if err = ctx.InsertBlankPages(pages, before); err != nil { + return err + } + + log.Stats.Printf("XRefTable:\n%s\n", ctx) + + if conf.ValidationMode != pdfcpu.ValidationNone { + if err = ValidateContext(ctx); err != nil { + return err + } + } + + if err = WriteContext(ctx, w); err != nil { + return err + } + + log.Stats.Printf("XRefTable:\n%s\n", ctx) + + return nil +} + +// InsertPagesFile inserts a blank page before or after every inFile page selected and writes the result to w. +func InsertPagesFile(inFile, outFile string, selectedPages []string, before bool, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return InsertPages(f1, f2, selectedPages, before, conf) +} + +// RemovePages removes selected pages from rs and writes the result to w. +func RemovePages(rs io.ReadSeeker, w io.Writer, selectedPages []string, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.REMOVEPAGES + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + fromWrite := time.Now() + + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, false) + if err != nil { + return err + } + + // ctx.Pagecount gets set during validation. + if len(pages) >= ctx.PageCount { + return errors.New("pdfcpu: operation invalid") + } + + // No special context processing required. + // WriteContext decides which pages get written by checking conf.Cmd + + ctx.Write.SelectedPages = pages + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "remove pages, write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// RemovePagesFile removes selected inFile pages and writes the result to outFile.. +func RemovePagesFile(inFile, outFile string, selectedPages []string, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return RemovePages(f1, f2, selectedPages, conf) +} + +// PageCount returns rs's page count. +func PageCount(rs io.ReadSeeker, conf *pdfcpu.Configuration) (int, error) { + ctx, err := ReadContext(rs, conf) + if err != nil { + return 0, err + } + if err := ValidateContext(ctx); err != nil { + return 0, err + } + return ctx.PageCount, nil +} + +// PageCountFile returns inFile's page count. +func PageCountFile(inFile string) (int, error) { + f, err := os.Open(inFile) + if err != nil { + return 0, err + } + defer f.Close() + + return PageCount(f, pdfcpu.NewDefaultConfiguration()) +} + +// PageDims returns a sorted slice of mediaBox dimensions for rs. +func PageDims(rs io.ReadSeeker, conf *pdfcpu.Configuration) ([]pdfcpu.Dim, error) { + ctx, err := ReadContext(rs, conf) + if err != nil { + return nil, err + } + + pd, err := ctx.PageDims() + if err != nil { + return nil, err + } + if len(pd) != ctx.PageCount { + return nil, errors.New("pdfcpu: corrupt page dimensions") + } + + return pd, nil +} + +// PageDimsFile returns a sorted slice of mediaBox dimensions for inFile. +func PageDimsFile(inFile string) ([]pdfcpu.Dim, error) { + f, err := os.Open(inFile) + if err != nil { + return nil, err + } + defer f.Close() + + return PageDims(f, pdfcpu.NewDefaultConfiguration()) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/permissions.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/permissions.go new file mode 100644 index 0000000..3d4e626 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/permissions.go @@ -0,0 +1,168 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// ListPermissions returns a list of user access permissions. +func ListPermissions(rs io.ReadSeeker, conf *pdfcpu.Configuration) ([]string, error) { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.LISTPERMISSIONS + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return nil, err + } + + fromList := time.Now() + list := pdfcpu.Permissions(ctx) + + durList := time.Since(fromList).Seconds() + durTotal := time.Since(fromStart).Seconds() + log.Stats.Printf("XRefTable:\n%s\n", ctx) + pdfcpu.TimingStats("list permissions", durRead, durVal, durOpt, durList, durTotal) + + return list, nil +} + +// ListPermissionsFile returns a list of user access permissions for inFile. +func ListPermissionsFile(inFile string, conf *pdfcpu.Configuration) ([]string, error) { + f, err := os.Open(inFile) + if err != nil { + return nil, err + } + + defer func() { + f.Close() + }() + + return ListPermissions(f, conf) +} + +// SetPermissions sets user access permissions. +// inFile has to be encrypted. +// A configuration containing the current passwords is required. +func SetPermissions(rs io.ReadSeeker, w io.Writer, conf *pdfcpu.Configuration) error { + if conf == nil { + return errors.New("pdfcpu: missing configuration for setting permissions") + } + conf.Cmd = pdfcpu.SETPERMISSIONS + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + fromWrite := time.Now() + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// SetPermissionsFile sets inFile's user access permissions. +// inFile has to be encrypted. +// A configuration containing the current passwords is required. +func SetPermissionsFile(inFile, outFile string, conf *pdfcpu.Configuration) (err error) { + if conf == nil { + return errors.New("pdfcpu: missing configuration for setting permissions") + } + + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return SetPermissions(f1, f2, conf) +} + +// GetPermissions returns the permissions for rs. +func GetPermissions(rs io.ReadSeeker, conf *pdfcpu.Configuration) (*int16, error) { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + ctx, _, _, err := readAndValidate(rs, conf, time.Now()) + if err != nil { + return nil, err + } + if ctx.E == nil { + // Full access - permissions don't apply. + return nil, nil + } + p := int16(ctx.E.P) + return &p, nil +} + +// GetPermissionsFile returns the permissions for inFile. +func GetPermissionsFile(inFile string, conf *pdfcpu.Configuration) (*int16, error) { + f, err := os.Open(inFile) + if err != nil { + return nil, err + } + defer f.Close() + + return GetPermissions(f, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/properties.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/properties.go new file mode 100644 index 0000000..a7d55cf --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/properties.go @@ -0,0 +1,221 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// ListProperties returns the property list of rs. +func ListProperties(rs io.ReadSeeker, conf *pdf.Configuration) ([]string, error) { + if conf == nil { + conf = pdf.NewDefaultConfiguration() + } else { + // Validation loads infodict. + conf.ValidationMode = pdf.ValidationRelaxed + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return nil, err + } + + fromWrite := time.Now() + list, err := pdf.PropertiesList(ctx.XRefTable) + if err != nil { + return nil, err + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + log.Stats.Printf("XRefTable:\n%s\n", ctx) + pdf.TimingStats("list files", durRead, durVal, durOpt, durWrite, durTotal) + + return list, nil +} + +// ListPropertiesFile returns the property list of inFile. +func ListPropertiesFile(inFile string, conf *pdf.Configuration) ([]string, error) { + f, err := os.Open(inFile) + if err != nil { + return nil, err + } + defer f.Close() + return ListProperties(f, conf) +} + +// AddProperties embeds files into a PDF context read from rs and writes the result to w. +func AddProperties(rs io.ReadSeeker, w io.Writer, properties map[string]string, conf *pdf.Configuration) error { + if conf == nil { + conf = pdf.NewDefaultConfiguration() + } else { + // Validation loads infodict. + conf.ValidationMode = pdf.ValidationRelaxed + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + from := time.Now() + + if err = pdf.PropertiesAdd(ctx.XRefTable, properties); err != nil { + return err + } + + durAdd := time.Since(from).Seconds() + fromWrite := time.Now() + + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := durAdd + time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "add keyword, write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// AddPropertiesFile embeds files into a PDF context read from inFile and writes the result to outFile. +func AddPropertiesFile(inFile, outFile string, properties map[string]string, conf *pdf.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + if outFile == "" || inFile == outFile { + os.Remove(tmpFile) + } + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return AddProperties(f1, f2, properties, conf) +} + +// RemoveProperties deletes embedded files from a PDF context read from rs and writes the result to w. +func RemoveProperties(rs io.ReadSeeker, w io.Writer, properties []string, conf *pdf.Configuration) error { + if conf == nil { + conf = pdf.NewDefaultConfiguration() + } else { + // Validation loads infodict. + conf.ValidationMode = pdf.ValidationRelaxed + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + from := time.Now() + + var ok bool + if ok, err = pdf.PropertiesRemove(ctx.XRefTable, properties); err != nil { + return err + } + if !ok { + return errors.New("no property removed") + } + + durRemove := time.Since(from).Seconds() + fromWrite := time.Now() + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := durRemove + time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "remove prop, write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// RemovePropertiesFile deletes embedded files from a PDF context read from inFile and writes the result to outFile. +func RemovePropertiesFile(inFile, outFile string, properties []string, conf *pdf.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + if outFile == "" || inFile == outFile { + os.Remove(tmpFile) + } + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return RemoveProperties(f1, f2, properties, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/rotate.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/rotate.go new file mode 100644 index 0000000..0caf58a --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/rotate.go @@ -0,0 +1,116 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" +) + +// Rotate rotates selected pages of rs clockwise by rotation degrees and writes the result to w. +func Rotate(rs io.ReadSeeker, w io.Writer, rotation int, selectedPages []string, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.ROTATE + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + from := time.Now() + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return err + } + + if err = pdfcpu.RotatePages(ctx, pages, rotation); err != nil { + return err + } + + log.Stats.Printf("XRefTable:\n%s\n", ctx) + durStamp := time.Since(from).Seconds() + fromWrite := time.Now() + + if conf.ValidationMode != pdfcpu.ValidationNone { + if err = ValidateContext(ctx); err != nil { + return err + } + } + + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := durStamp + time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "rotate, write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// RotateFile rotates selected pages of inFile clockwise by rotation degrees and writes the result to outFile. +func RotateFile(inFile, outFile string, rotation int, selectedPages []string, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return Rotate(f1, f2, rotation, selectedPages, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/selectPages.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/selectPages.go new file mode 100644 index 0000000..c3802c3 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/selectPages.go @@ -0,0 +1,651 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package api + +import ( + "fmt" + "regexp" + "sort" + "strconv" + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/log" + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +var ( + selectedPagesRegExp *regexp.Regexp +) + +func setupRegExpForPageSelection() *regexp.Regexp { + e := "(\\d+)?-l(-\\d+)?|l(-(\\d+)-?)?" + e = "[!n]?((-\\d+)|(\\d+(-(\\d+)?)?)|" + e + ")" + e = "\\Qeven\\E|\\Qodd\\E|" + e + exp := "^" + e + "(," + e + ")*$" + re, _ := regexp.Compile(exp) + return re +} + +func init() { + selectedPagesRegExp = setupRegExpForPageSelection() +} + +// ParsePageSelection ensures a correct page selection expression. +func ParsePageSelection(s string) ([]string, error) { + if s == "" { + return nil, nil + } + + // Ensure valid comma separated expression of:{ {even|odd}{!}{-}# | {even|odd}{!}#-{#} }* + // + // Negated expressions: + // '!' negates an expression + // since '!' needs to be part of a single quoted string in bash + // as an alternative also 'n' works instead of "!" + // + // Extract all but page 4 may be expressed as: "1-,!4" or "1-,n4" + // + // The pageSelection is evaluated strictly from left to right! + // e.g. "!3,1-5" extracts pages 1-5 whereas "1-5,!3" extracts pages 1,2,4,5 + // + + if !selectedPagesRegExp.MatchString(s) { + return nil, errors.Errorf("-pages \"%s\" => syntax error\n", s) + } + + //log.CLI.Printf("pageSelection: %s\n", s) + + return strings.Split(s, ","), nil +} + +func handlePrefix(v string, negated bool, pageCount int, selectedPages pdf.IntSet) error { + // -l + if v == "l" { + for j := 1; j <= pageCount; j++ { + selectedPages[j] = !negated + } + return nil + } + + // -l-# + if strings.HasPrefix(v, "l-") { + i, err := strconv.Atoi(v[2:]) + if err != nil { + return err + } + if pageCount-i < 1 { + return nil + } + for j := 1; j <= pageCount-i; j++ { + selectedPages[j] = !negated + } + return nil + } + + // -# + i, err := strconv.Atoi(v) + if err != nil { + return err + } + + // Handle overflow gracefully + if i > pageCount { + i = pageCount + } + + // identified + // -# ... select all pages up to and including # + // or !-# ... deselect all pages up to and including # + for j := 1; j <= i; j++ { + selectedPages[j] = !negated + } + + return nil +} + +func handleSuffix(v string, negated bool, pageCount int, selectedPages pdf.IntSet) error { + // must be #- ... select all pages from here until the end. + // or !#- ... deselect all pages from here until the end. + + i, err := strconv.Atoi(v) + if err != nil { + return err + } + + // Handle overflow gracefully + if i > pageCount { + return nil + } + + for j := i; j <= pageCount; j++ { + selectedPages[j] = !negated + } + + return nil +} + +func handleSpecificPageOrLastXPages(s string, negated bool, pageCount int, selectedPages pdf.IntSet) error { + + // l + if s == "l" { + selectedPages[pageCount] = !negated + return nil + } + + // l-# + if strings.HasPrefix(s, "l-") { + pr := strings.Split(s[2:], "-") + i, err := strconv.Atoi(pr[0]) + if err != nil { + return err + } + if pageCount-i < 1 { + return nil + } + j := pageCount - i + + // l-#- + if strings.HasSuffix(s, "-") { + j = pageCount + } + for i := pageCount - i; i <= j; i++ { + selectedPages[i] = !negated + } + return nil + } + + // must be # ... select a specific page + // or !# ... deselect a specific page + i, err := strconv.Atoi(s) + if err != nil { + return err + } + + // Handle overflow gracefully + if i > pageCount { + return nil + } + + selectedPages[i] = !negated + + return nil +} + +func negation(c byte) bool { + return c == '!' || c == 'n' +} + +func selectEvenPages(selectedPages pdf.IntSet, pageCount int) { + for i := 2; i <= pageCount; i += 2 { + _, found := selectedPages[i] + if !found { + selectedPages[i] = true + } + } +} + +func selectOddPages(selectedPages pdf.IntSet, pageCount int) { + for i := 1; i <= pageCount; i += 2 { + _, found := selectedPages[i] + if !found { + selectedPages[i] = true + } + } +} + +func parsePageRange(pr []string, pageCount int, negated bool, selectedPages pdf.IntSet) error { + from, err := strconv.Atoi(pr[0]) + if err != nil { + return err + } + + // Handle overflow gracefully + if from > pageCount { + return nil + } + + var thru int + if pr[1] == "l" { + // #-l + thru = pageCount + if len(pr) == 3 { + // #-l-# + i, err := strconv.Atoi(pr[2]) + if err != nil { + return err + } + thru -= i + } + } else { + // #-# + var err error + thru, err = strconv.Atoi(pr[1]) + if err != nil { + return err + } + } + + // Handle overflow gracefully + if thru < from { + return nil + } + + if thru > pageCount { + thru = pageCount + } + + for i := from; i <= thru; i++ { + selectedPages[i] = !negated + } + + return nil +} + +func sortedPages(selectedPages pdf.IntSet) []int { + p := []int(nil) + for i, v := range selectedPages { + if v { + p = append(p, i) + } + } + sort.Ints(p) + return p +} + +func logSelPages(selectedPages pdf.IntSet) { + if !log.IsCLILoggerEnabled() { + return + } + var b strings.Builder + for _, i := range sortedPages(selectedPages) { + fmt.Fprintf(&b, "%d,", i) + } + s := b.String() + if len(s) > 1 { + s = s[:len(s)-1] + } + log.CLI.Printf("pages: %s\n", s) +} + +// selectedPages returns a set of used page numbers. +// key==page# => key 0 unused! +func selectedPages(pageCount int, pageSelection []string) (pdf.IntSet, error) { + selectedPages := pdf.IntSet{} + + for _, v := range pageSelection { + + //log.Stats.Printf("pageExp: <%s>\n", v) + + if v == "even" { + selectEvenPages(selectedPages, pageCount) + continue + } + + if v == "odd" { + selectOddPages(selectedPages, pageCount) + continue + } + + var negated bool + if negation(v[0]) { + negated = true + //logInfoAPI.Printf("is a negated exp\n") + v = v[1:] + } + + // -# + if v[0] == '-' { + + v = v[1:] + + if err := handlePrefix(v, negated, pageCount, selectedPages); err != nil { + return nil, err + } + + continue + } + + // #- + if v[0] != 'l' && strings.HasSuffix(v, "-") { + + if err := handleSuffix(v[:len(v)-1], negated, pageCount, selectedPages); err != nil { + return nil, err + } + + continue + } + + // l l-# l-#- + if v[0] == 'l' { + if err := handleSpecificPageOrLastXPages(v, negated, pageCount, selectedPages); err != nil { + return nil, err + } + continue + } + + pr := strings.Split(v, "-") + if len(pr) >= 2 { + // v contains '-' somewhere in the middle + // #-# #-l #-l-# + if err := parsePageRange(pr, pageCount, negated, selectedPages); err != nil { + return nil, err + } + + continue + } + + // # + if err := handleSpecificPageOrLastXPages(pr[0], negated, pageCount, selectedPages); err != nil { + return nil, err + } + + } + + logSelPages(selectedPages) + return selectedPages, nil +} + +// PagesForPageSelection ensures a set of page numbers for an ascending page sequence +// where each page number may appear only once. +func PagesForPageSelection(pageCount int, pageSelection []string, ensureAllforNone bool) (pdf.IntSet, error) { + if pageSelection != nil && len(pageSelection) > 0 { + return selectedPages(pageCount, pageSelection) + } + if !ensureAllforNone { + //log.CLI.Printf("pages: none\n") + return nil, nil + } + m := pdf.IntSet{} + for i := 1; i <= pageCount; i++ { + m[i] = true + } + log.CLI.Printf("pages: all\n") + return m, nil +} + +func deletePageFromCollection(cp *[]int, p int) { + a := []int{} + for _, i := range *cp { + if i != p { + a = append(a, i) + } + } + *cp = a +} + +func processPageForCollection(cp *[]int, negated bool, i int) { + if !negated { + *cp = append(*cp, i) + } else { + deletePageFromCollection(cp, i) + } +} + +func collectEvenPages(cp *[]int, pageCount int) { + for i := 2; i <= pageCount; i += 2 { + *cp = append(*cp, i) + } +} + +func collectOddPages(cp *[]int, pageCount int) { + for i := 1; i <= pageCount; i += 2 { + *cp = append(*cp, i) + } +} + +func handlePrefixForCollection(v string, negated bool, pageCount int, cp *[]int) error { + // -l + if v == "l" { + for j := 1; j <= pageCount; j++ { + processPageForCollection(cp, negated, j) + } + return nil + } + + // -l-# + if strings.HasPrefix(v, "l-") { + i, err := strconv.Atoi(v[2:]) + if err != nil { + return err + } + if pageCount-i < 1 { + return nil + } + for j := 1; j <= pageCount-i; j++ { + processPageForCollection(cp, negated, j) + } + return nil + } + + // -# + i, err := strconv.Atoi(v) + if err != nil { + return err + } + + // Handle overflow gracefully + if i > pageCount { + i = pageCount + } + + // identified + // -# ... select all pages up to and including # + // or !-# ... deselect all pages up to and including # + for j := 1; j <= i; j++ { + processPageForCollection(cp, negated, j) + } + + return nil +} + +func handleSuffixForCollection(v string, negated bool, pageCount int, cp *[]int) error { + // must be #- ... select all pages from here until the end. + // or !#- ... deselect all pages from here until the end. + + i, err := strconv.Atoi(v) + if err != nil { + return err + } + + // Handle overflow gracefully + if i > pageCount { + return nil + } + + for j := i; j <= pageCount; j++ { + processPageForCollection(cp, negated, j) + } + + return nil +} + +func handleSpecificPageOrLastXPagesForCollection(s string, negated bool, pageCount int, cp *[]int) error { + + // l + if s == "l" { + processPageForCollection(cp, negated, pageCount) + return nil + } + + // l-# + if strings.HasPrefix(s, "l-") { + pr := strings.Split(s[2:], "-") + i, err := strconv.Atoi(pr[0]) + if err != nil { + return err + } + if pageCount-i < 1 { + return nil + } + j := pageCount - i + + // l-#- + if strings.HasSuffix(s, "-") { + j = pageCount + } + for i := pageCount - i; i <= j; i++ { + processPageForCollection(cp, negated, i) + } + return nil + } + + // must be # ... select a specific page + // or !# ... deselect a specific page + i, err := strconv.Atoi(s) + if err != nil { + return err + } + + // Handle overflow gracefully + if i > pageCount { + return nil + } + + processPageForCollection(cp, negated, i) + + return nil +} + +func parsePageRangeForCollection(pr []string, pageCount int, negated bool, cp *[]int) error { + from, err := strconv.Atoi(pr[0]) + if err != nil { + return err + } + + // Handle overflow gracefully + if from > pageCount { + return nil + } + + var thru int + if pr[1] == "l" { + // #-l + thru = pageCount + if len(pr) == 3 { + // #-l-# + i, err := strconv.Atoi(pr[2]) + if err != nil { + return err + } + thru -= i + } + } else { + // #-# + var err error + thru, err = strconv.Atoi(pr[1]) + if err != nil { + return err + } + } + + // Handle overflow gracefully + if thru < from { + return nil + } + + if thru > pageCount { + thru = pageCount + } + + for i := from; i <= thru; i++ { + processPageForCollection(cp, negated, i) + } + + return nil +} + +// PagesForPageCollection returns a slice of page numbers for a page collection. +// Any page number in any order any number of times allowed. +func PagesForPageCollection(pageCount int, pageSelection []string) ([]int, error) { + collectedPages := []int{} + for _, v := range pageSelection { + + if v == "even" { + collectEvenPages(&collectedPages, pageCount) + continue + } + + if v == "odd" { + collectOddPages(&collectedPages, pageCount) + continue + } + + var negated bool + if negation(v[0]) { + negated = true + //logInfoAPI.Printf("is a negated exp\n") + v = v[1:] + } + + // -# + if v[0] == '-' { + + v = v[1:] + + if err := handlePrefixForCollection(v, negated, pageCount, &collectedPages); err != nil { + return nil, err + } + + continue + } + + // #- + if v[0] != 'l' && strings.HasSuffix(v, "-") { + + if err := handleSuffixForCollection(v[:len(v)-1], negated, pageCount, &collectedPages); err != nil { + return nil, err + } + + continue + } + + // l l-# l-#- + if v[0] == 'l' { + if err := handleSpecificPageOrLastXPagesForCollection(v, negated, pageCount, &collectedPages); err != nil { + return nil, err + } + continue + } + + pr := strings.Split(v, "-") + if len(pr) >= 2 { + // v contains '-' somewhere in the middle + // #-# #-l #-l-# + if err := parsePageRangeForCollection(pr, pageCount, negated, &collectedPages); err != nil { + return nil, err + } + + continue + } + + // # + if err := handleSpecificPageOrLastXPagesForCollection(pr[0], negated, pageCount, &collectedPages); err != nil { + return nil, err + } + } + return collectedPages, nil +} + +// PagesForPageRange returns a slice of page numbers for a page range. +func PagesForPageRange(from, thru int) []int { + s := make([]int, thru-from+1) + for i := 0; i < len(s); i++ { + s[i] = from + i + } + return s +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/split.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/split.go new file mode 100644 index 0000000..9e1b548 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/split.go @@ -0,0 +1,186 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "path/filepath" + "strconv" + "strings" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" +) + +func spanFileName(fileName string, from, thru int) string { + baseFileName := filepath.Base(fileName) + fn := strings.TrimSuffix(baseFileName, ".pdf") + fn = fn + "_" + strconv.Itoa(from) + if from == thru { + return fn + ".pdf" + } + return fn + "-" + strconv.Itoa(thru) + ".pdf" +} + +func writeSpan(ctx *pdfcpu.Context, from, thru int, outDir, fileName string, forBookmark bool) error { + selectedPages := PagesForPageRange(from, thru) + + ctxDest, err := pdfcpu.CreateContextWithXRefTable(nil, pdfcpu.PaperSize["A4"]) + if err != nil { + return err + } + + usePgCache := false + if err := pdfcpu.AddPages(ctx, ctxDest, selectedPages, usePgCache); err != nil { + return err + } + + w := ctxDest.Write + w.DirName = outDir + w.FileName = fileName + ".pdf" + if !forBookmark { + w.FileName = spanFileName(fileName, from, thru) + //log.CLI.Printf("writing to: <%s>\n", w.FileName) + } + + return pdfcpu.Write(ctxDest) +} + +func writePageSpan(ctx *pdfcpu.Context, from, thru int, outDir, fileName string, forBookmark bool) error { + selectedPages := PagesForPageRange(from, thru) + + // Create context with copies of selectedPages. + ctxNew, err := ctx.ExtractPages(selectedPages, false) + if err != nil { + return err + } + + // Write context to file. + outFile := filepath.Join(outDir, fileName+".pdf") + if !forBookmark { + outFile = filepath.Join(outDir, spanFileName(fileName, from, thru)) + } + + return WriteContextFile(ctxNew, outFile) +} + +func writePageSpansSplitAlongBookmarks(ctx *pdfcpu.Context, outDir string) error { + bms, err := ctx.BookmarksForOutlineLevel1() + if err != nil { + return err + } + for _, bm := range bms { + fileName := bm.Title + from := bm.PageFrom + thru := bm.PageThru + if thru == 0 { + thru = ctx.PageCount + } + forBookmark := true + if err := writePageSpan(ctx, from, thru, outDir, fileName, forBookmark); err != nil { + return err + } + } + return nil +} + +func writePageSpans(ctx *pdfcpu.Context, span int, outDir, fileName string) error { + if span == 0 { + return writePageSpansSplitAlongBookmarks(ctx, outDir) + } + + forBookmark := false + + for i := 0; i < ctx.PageCount/span; i++ { + start := i * span + from := start + 1 + thru := start + span + if err := writePageSpan(ctx, from, thru, outDir, fileName, forBookmark); err != nil { + return err + } + } + + // A possible last file has less than span pages. + if ctx.PageCount%span > 0 { + start := (ctx.PageCount / span) * span + from := start + 1 + thru := ctx.PageCount + if err := writePageSpan(ctx, from, thru, outDir, fileName, forBookmark); err != nil { + return err + } + } + + return nil +} + +// Split generates a sequence of PDF files in outDir for the PDF stream read from rs obeying given split span. +// If span == 1 splitting results in single page PDFs. +// If span == 0 we split along given bookmarks (level 1 only). +// Default span: 1 +func Split(rs io.ReadSeeker, outDir, fileName string, span int, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.SPLIT + + fromStart := time.Now() + + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + fromWrite := time.Now() + + if err = writePageSpans(ctx, span, outDir, fileName); err != nil { + return err + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "split", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// SplitFile generates a sequence of PDF files in outDir for inFile obeying given split span. +// If span == 1 splitting results in single page PDFs. +// If span == 0 we split along given bookmarks (level 1 only). +// Default span: 1 +func SplitFile(inFile, outDir string, span int, conf *pdfcpu.Configuration) error { + f, err := os.Open(inFile) + if err != nil { + return err + } + log.CLI.Printf("splitting %s to %s/...\n", inFile, outDir) + + defer func() { + if err != nil { + f.Close() + return + } + err = f.Close() + }() + + return Split(f, outDir, filepath.Base(inFile), span, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/stamp.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/stamp.go new file mode 100644 index 0000000..724f18e --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/stamp.go @@ -0,0 +1,442 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// WatermarkContext applies wm for selected pages to ctx. +func WatermarkContext(ctx *pdfcpu.Context, selectedPages pdfcpu.IntSet, wm *pdfcpu.Watermark) error { + return ctx.AddWatermarks(selectedPages, wm) +} + +// AddWatermarksMap adds watermarks in m to corresponding pages in rs and writes the result to w. +func AddWatermarksMap(rs io.ReadSeeker, w io.Writer, m map[int]*pdfcpu.Watermark, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.ADDWATERMARKS + + if len(m) == 0 { + return errors.New("pdfcpu: missing watermarks") + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + from := time.Now() + + if err = ctx.AddWatermarksMap(m); err != nil { + return err + } + + log.Stats.Printf("XRefTable:\n%s\n", ctx) + + if conf.ValidationMode != pdfcpu.ValidationNone { + if err = ValidateContext(ctx); err != nil { + return err + } + } + + durStamp := time.Since(from).Seconds() + fromWrite := time.Now() + + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := durStamp + time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "watermark, write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// AddWatermarksMapFile adds watermarks to corresponding pages in m of inFile and writes the result to outFile. +func AddWatermarksMapFile(inFile, outFile string, m map[int]*pdfcpu.Watermark, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return AddWatermarksMap(f1, f2, m, conf) +} + +// AddWatermarks adds watermarks to all pages selected in rs and writes the result to w. +func AddWatermarks(rs io.ReadSeeker, w io.Writer, selectedPages []string, wm *pdfcpu.Watermark, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.ADDWATERMARKS + + if wm == nil { + return errors.New("pdfcpu: missing watermark configuration") + } + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + from := time.Now() + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return err + } + + if err = ctx.AddWatermarks(pages, wm); err != nil { + return err + } + + log.Stats.Printf("XRefTable:\n%s\n", ctx) + + if conf.ValidationMode != pdfcpu.ValidationNone { + if err = ValidateContext(ctx); err != nil { + return err + } + } + + durStamp := time.Since(from).Seconds() + fromWrite := time.Now() + + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := durStamp + time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "watermark, write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// AddWatermarksFile adds watermarks to all selected pages of inFile and writes the result to outFile. +func AddWatermarksFile(inFile, outFile string, selectedPages []string, wm *pdfcpu.Watermark, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return AddWatermarks(f1, f2, selectedPages, wm, conf) +} + +// RemoveWatermarks removes watermarks from all pages selected in rs and writes the result to w. +func RemoveWatermarks(rs io.ReadSeeker, w io.Writer, selectedPages []string, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.REMOVEWATERMARKS + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + from := time.Now() + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true) + if err != nil { + return err + } + + if err = ctx.RemoveWatermarks(pages); err != nil { + return err + } + + log.Stats.Printf("XRefTable:\n%s\n", ctx) + + if conf.ValidationMode != pdfcpu.ValidationNone { + if err = ValidateContext(ctx); err != nil { + return err + } + } + + durStamp := time.Since(from).Seconds() + fromWrite := time.Now() + + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := durStamp + time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "watermark, write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// RemoveWatermarksFile removes watermarks from all selected pages of inFile and writes the result to outFile. +func RemoveWatermarksFile(inFile, outFile string, selectedPages []string, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return RemoveWatermarks(f1, f2, selectedPages, conf) +} + +// HasWatermarks checks rs for watermarks. +func HasWatermarks(rs io.ReadSeeker, conf *pdfcpu.Configuration) (bool, error) { + ctx, err := ReadContext(rs, conf) + if err != nil { + return false, err + } + if err := ctx.DetectWatermarks(); err != nil { + return false, err + } + + return ctx.Watermarked, nil +} + +// HasWatermarksFile checks inFile for watermarks. +func HasWatermarksFile(inFile string, conf *pdfcpu.Configuration) (bool, error) { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + + f, err := os.Open(inFile) + if err != nil { + return false, err + } + + defer f.Close() + + return HasWatermarks(f, conf) +} + +// TextWatermark returns a text watermark configuration. +func TextWatermark(text, desc string, onTop, update bool, u pdfcpu.DisplayUnit) (*pdfcpu.Watermark, error) { + wm, err := pdfcpu.ParseTextWatermarkDetails(text, desc, onTop, u) + if err != nil { + return nil, err + } + wm.Update = update + return wm, nil +} + +// ImageWatermark returns an image watermark configuration. +func ImageWatermark(fileName, desc string, onTop, update bool, u pdfcpu.DisplayUnit) (*pdfcpu.Watermark, error) { + wm, err := pdfcpu.ParseImageWatermarkDetails(fileName, desc, onTop, u) + if err != nil { + return nil, err + } + wm.Update = update + return wm, nil +} + +// PDFWatermark returns a PDF watermark configuration. +func PDFWatermark(fileName, desc string, onTop, update bool, u pdfcpu.DisplayUnit) (*pdfcpu.Watermark, error) { + wm, err := pdfcpu.ParsePDFWatermarkDetails(fileName, desc, onTop, u) + if err != nil { + return nil, err + } + wm.Update = update + return wm, nil +} + +// AddTextWatermarksFile adds text stamps/watermarks to all selected pages of inFile and writes the result to outFile. +func AddTextWatermarksFile(inFile, outFile string, selectedPages []string, onTop bool, text, desc string, conf *pdfcpu.Configuration) error { + unit := pdfcpu.POINTS + if conf != nil { + unit = conf.Unit + } + wm, err := TextWatermark(text, desc, onTop, false, unit) + if err != nil { + return err + } + return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf) +} + +// AddImageWatermarksFile adds image stamps/watermarks to all selected pages of inFile and writes the result to outFile. +func AddImageWatermarksFile(inFile, outFile string, selectedPages []string, onTop bool, fileName, desc string, conf *pdfcpu.Configuration) error { + unit := pdfcpu.POINTS + if conf != nil { + unit = conf.Unit + } + wm, err := ImageWatermark(fileName, desc, onTop, false, unit) + if err != nil { + return err + } + return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf) +} + +// AddPDFWatermarksFile adds PDF stamps/watermarks to all selected pages of inFile and writes the result to outFile. +func AddPDFWatermarksFile(inFile, outFile string, selectedPages []string, onTop bool, fileName, desc string, conf *pdfcpu.Configuration) error { + unit := pdfcpu.POINTS + if conf != nil { + unit = conf.Unit + } + wm, err := PDFWatermark(fileName, desc, onTop, false, unit) + if err != nil { + return err + } + return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf) +} + +// UpdateTextWatermarksFile adds text stamps/watermarks to all selected pages of inFile and writes the result to outFile. +func UpdateTextWatermarksFile(inFile, outFile string, selectedPages []string, onTop bool, text, desc string, conf *pdfcpu.Configuration) error { + unit := pdfcpu.POINTS + if conf != nil { + unit = conf.Unit + } + wm, err := TextWatermark(text, desc, onTop, true, unit) + if err != nil { + return err + } + return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf) +} + +// UpdateImageWatermarksFile adds image stamps/watermarks to all selected pages of inFile and writes the result to outFile. +func UpdateImageWatermarksFile(inFile, outFile string, selectedPages []string, onTop bool, fileName, desc string, conf *pdfcpu.Configuration) error { + unit := pdfcpu.POINTS + if conf != nil { + unit = conf.Unit + } + wm, err := ImageWatermark(fileName, desc, onTop, true, unit) + if err != nil { + return err + } + return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf) +} + +// UpdatePDFWatermarksFile adds PDF stamps/watermarks to all selected pages of inFile and writes the result to outFile. +func UpdatePDFWatermarksFile(inFile, outFile string, selectedPages []string, onTop bool, fileName, desc string, conf *pdfcpu.Configuration) error { + unit := pdfcpu.POINTS + if conf != nil { + unit = conf.Unit + } + wm, err := PDFWatermark(fileName, desc, onTop, true, unit) + if err != nil { + return err + } + return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/trim.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/trim.go new file mode 100644 index 0000000..7c96ebd --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/trim.go @@ -0,0 +1,109 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" +) + +// Trim generates a trimmed version of rs +// containing all selected pages and writes the result to w. +func Trim(rs io.ReadSeeker, w io.Writer, selectedPages []string, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.TRIM + + fromStart := time.Now() + ctx, durRead, durVal, durOpt, err := readValidateAndOptimize(rs, conf, fromStart) + if err != nil { + return err + } + + if err := ctx.EnsurePageCount(); err != nil { + return err + } + + fromWrite := time.Now() + + pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, false) + if err != nil { + return err + } + + // No special context processing required. + // WriteContext decides which pages get written by checking conf.Cmd + + ctx.Write.SelectedPages = pages + if err = WriteContext(ctx, w); err != nil { + return err + } + + durWrite := time.Since(fromWrite).Seconds() + durTotal := time.Since(fromStart).Seconds() + logOperationStats(ctx, "trim, write", durRead, durVal, durOpt, durWrite, durTotal) + + return nil +} + +// TrimFile generates a trimmed version of inFile +// containing all selected pages and writes the result to outFile. +func TrimFile(inFile, outFile string, selectedPages []string, conf *pdfcpu.Configuration) (err error) { + var f1, f2 *os.File + + if f1, err = os.Open(inFile); err != nil { + return err + } + + tmpFile := inFile + ".tmp" + if outFile != "" && inFile != outFile { + tmpFile = outFile + log.CLI.Printf("writing %s...\n", outFile) + } else { + log.CLI.Printf("writing %s...\n", inFile) + } + if f2, err = os.Create(tmpFile); err != nil { + return err + } + + defer func() { + if err != nil { + f2.Close() + f1.Close() + os.Remove(tmpFile) + return + } + if err = f2.Close(); err != nil { + return + } + if err = f1.Close(); err != nil { + return + } + if outFile == "" || inFile == outFile { + if err = os.Rename(tmpFile, inFile); err != nil { + return + } + } + }() + + return Trim(f1, f2, selectedPages, conf) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/api/validate.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/validate.go new file mode 100644 index 0000000..ebef3d4 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/api/validate.go @@ -0,0 +1,98 @@ +/* + Copyright 2020 The pdfcpu Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package api + +import ( + "io" + "os" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// Validate validates a PDF stream read from rs. +func Validate(rs io.ReadSeeker, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + conf.Cmd = pdfcpu.VALIDATE + + if conf.ValidationMode == pdfcpu.ValidationNone { + return errors.New("pdfcpu: validate: mode ValidationNone not allowed") + } + + from1 := time.Now() + + ctx, err := ReadContext(rs, conf) + if err != nil { + return err + } + + dur1 := time.Since(from1).Seconds() + from2 := time.Now() + + if err = ValidateContext(ctx); err != nil { + s := "" + if conf.ValidationMode == pdfcpu.ValidationStrict { + s = " (try -mode=relaxed)" + } + err = errors.Wrap(err, "validation error"+s) + } + + dur2 := time.Since(from2).Seconds() + dur := time.Since(from1).Seconds() + + log.Stats.Printf("XRefTable:\n%s\n", ctx) + pdfcpu.ValidationTimingStats(dur1, dur2, dur) + + // at this stage: no binary breakup available! + if ctx.Read.FileSize > 0 { + ctx.Read.LogStats(ctx.Optimized) + } + + return err +} + +// ValidateFile validates inFile. +func ValidateFile(inFile string, conf *pdfcpu.Configuration) error { + if conf == nil { + conf = pdfcpu.NewDefaultConfiguration() + } + + if conf != nil && conf.ValidationMode == pdfcpu.ValidationNone { + return nil + } + + log.CLI.Printf("validating(mode=%s) %s ...\n", conf.ValidationModeString(), inFile) + + f, err := os.Open(inFile) + if err != nil { + return err + } + + defer f.Close() + + if err = Validate(f, conf); err != nil { + return err + } + + log.CLI.Println("validation ok") + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/ascii85Decode.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/ascii85Decode.go new file mode 100644 index 0000000..9394857 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/ascii85Decode.go @@ -0,0 +1,76 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filter + +import ( + "bytes" + "encoding/ascii85" + "io" + "io/ioutil" + + "github.com/pkg/errors" +) + +type ascii85Decode struct { + baseFilter +} + +const eodASCII85 = "~>" + +// Encode implements encoding for an ASCII85Decode filter. +func (f ascii85Decode) Encode(r io.Reader) (io.Reader, error) { + + p, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + buf := &bytes.Buffer{} + encoder := ascii85.NewEncoder(buf) + encoder.Write(p) + encoder.Close() + + // Add eod sequence + buf.WriteString(eodASCII85) + + return buf, nil +} + +// Decode implements decoding for an ASCII85Decode filter. +func (f ascii85Decode) Decode(r io.Reader) (io.Reader, error) { + + p, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + if !bytes.HasSuffix(p, []byte(eodASCII85)) { + return nil, errors.New("pdfcpu: Decode: missing eod marker") + } + + // Strip eod sequence: "~>" + p = p[:len(p)-2] + + decoder := ascii85.NewDecoder(bytes.NewReader(p)) + + buf, err := ioutil.ReadAll(decoder) + if err != nil { + return nil, err + } + + return bytes.NewBuffer(buf), nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/asciiHexDecode.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/asciiHexDecode.go new file mode 100644 index 0000000..4f55181 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/asciiHexDecode.go @@ -0,0 +1,82 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filter + +import ( + "bytes" + "encoding/hex" + "io" + "io/ioutil" +) + +type asciiHexDecode struct { + baseFilter +} + +const eodHexDecode = '>' + +// Encode implements encoding for an ASCIIHexDecode filter. +func (f asciiHexDecode) Encode(r io.Reader) (io.Reader, error) { + + bb, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + dst := make([]byte, hex.EncodedLen(len(bb))) + hex.Encode(dst, bb) + + // eod marker + dst = append(dst, eodHexDecode) + + return bytes.NewBuffer(dst), nil +} + +// Decode implements decoding for an ASCIIHexDecode filter. +func (f asciiHexDecode) Decode(r io.Reader) (io.Reader, error) { + + bb, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + var p []byte + + // Remove any white space and cut off on eod + for i := 0; i < len(bb); i++ { + if bb[i] == eodHexDecode { + break + } + if !bytes.ContainsRune([]byte{0x09, 0x0A, 0x0C, 0x0D, 0x20}, rune(bb[i])) { + p = append(p, bb[i]) + } + } + + // if len == odd add "0" + if len(p)%2 == 1 { + p = append(p, '0') + } + + dst := make([]byte, hex.DecodedLen(len(p))) + + _, err = hex.Decode(dst, p) + if err != nil { + return nil, err + } + + return bytes.NewBuffer(dst), nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/ccittDecode.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/ccittDecode.go new file mode 100644 index 0000000..0a4abe0 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/ccittDecode.go @@ -0,0 +1,93 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filter + +import ( + "bytes" + "io" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" + "golang.org/x/image/ccitt" +) + +type ccittDecode struct { + baseFilter +} + +// Encode implements encoding for an CCITTDecode filter. +func (f ccittDecode) Encode(r io.Reader) (io.Reader, error) { + // TODO + return nil, nil +} + +// Decode implements decoding for a CCITTDecode filter. +func (f ccittDecode) Decode(r io.Reader) (io.Reader, error) { + + log.Trace.Println("DecodeCCITT begin") + + var ok bool + + // <0 : Pure two-dimensional encoding (Group 4) + // =0 : Pure one-dimensional encoding (Group 3, 1-D) + // >0 : Mixed one- and two-dimensional encoding (Group 3, 2-D) + k := 0 + k, ok = f.parms["K"] + if ok && k > 0 { + return nil, errors.New("pdfcpu: filter CCITTFax k > 0 currently unsupported") + } + + cols := 1728 + col, ok := f.parms["Columns"] + if ok { + cols = col + } + + rows, ok := f.parms["Rows"] + if !ok { + return nil, errors.New("pdfcpu: ccitt: missing DecodeParam \"Rows\"") + } + + blackIs1 := false + v, ok := f.parms["BlackIs1"] + if ok && v == 1 { + blackIs1 = true + } + + encodedByteAlign := false + v, ok = f.parms["EncodedByteAlign"] + if ok && v == 1 { + encodedByteAlign = true + } + + opts := &ccitt.Options{Invert: blackIs1, Align: encodedByteAlign} + + mode := ccitt.Group3 + if k < 0 { + mode = ccitt.Group4 + } + rd := ccitt.NewReader(r, ccitt.MSB, mode, cols, rows, opts) + + var b bytes.Buffer + written, err := io.Copy(&b, rd) + if err != nil { + return nil, err + } + log.Trace.Printf("DecodeCCITT: decoded %d bytes.\n", written) + + return &b, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/filter.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/filter.go new file mode 100644 index 0000000..7119e4b --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/filter.go @@ -0,0 +1,99 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package filter contains PDF filter implementations. +package filter + +import ( + "io" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +// PDF defines the following filters. See also 7.4 in the PDF spec. +const ( + ASCII85 = "ASCII85Decode" + ASCIIHex = "ASCIIHexDecode" + RunLength = "RunLengthDecode" + LZW = "LZWDecode" + Flate = "FlateDecode" + CCITTFax = "CCITTFaxDecode" + JBIG2 = "JBIG2Decode" + DCT = "DCTDecode" + JPX = "JPXDecode" +) + +// ErrUnsupportedFilter signals unsupported filter encountered. +var ErrUnsupportedFilter = errors.New("pdfcpu: filter not supported") + +// Filter defines an interface for encoding/decoding PDF object streams. +type Filter interface { + Encode(r io.Reader) (io.Reader, error) + Decode(r io.Reader) (io.Reader, error) +} + +// NewFilter returns a filter for given filterName and an optional parameter dictionary. +func NewFilter(filterName string, parms map[string]int) (filter Filter, err error) { + switch filterName { + + case ASCII85: + filter = ascii85Decode{baseFilter{}} + + case ASCIIHex: + filter = asciiHexDecode{baseFilter{}} + + case RunLength: + filter = runLengthDecode{baseFilter{parms}} + + case LZW: + filter = lzwDecode{baseFilter{parms}} + + case Flate: + filter = flate{baseFilter{parms}} + + case CCITTFax: + filter = ccittDecode{baseFilter{parms}} + + case DCT: + // Unsupported + fallthrough + + case JBIG2: + // Unsupported + fallthrough + + case JPX: + // Unsupported + log.Info.Printf("Filter not supported: <%s>", filterName) + err = ErrUnsupportedFilter + + default: + err = errors.Errorf("Invalid filter: <%s>", filterName) + } + + return filter, err +} + +// List return the list of all supported PDF filters. +func List() []string { + // Exclude CCITTFax, DCT, JBIG2 & JPX since they only makes sense in the context of image processing. + return []string{ASCII85, ASCIIHex, RunLength, LZW, Flate} +} + +type baseFilter struct { + parms map[string]int +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/flateDecode.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/flateDecode.go new file mode 100644 index 0000000..e5ee1e3 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/flateDecode.go @@ -0,0 +1,335 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filter + +import ( + "bytes" + "compress/zlib" + "io" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +// Portions of this code are based on ideas of image/png: reader.go:readImagePass +// PNG is documented here: www.w3.org/TR/PNG-Filters.html + +// PDF allows a prediction step prior to compression applying TIFF or PNG prediction. +// Predictor algorithm. +const ( + PredictorNo = 1 // No prediction. + PredictorTIFF = 2 // Use TIFF prediction for all rows. + PredictorNone = 10 // Use PNGNone for all rows. + PredictorSub = 11 // Use PNGSub for all rows. + PredictorUp = 12 // Use PNGUp for all rows. + PredictorAverage = 13 // Use PNGAverage for all rows. + PredictorPaeth = 14 // Use PNGPaeth for all rows. + PredictorOptimum = 15 // Use the optimum PNG prediction for each row. +) + +// For predictor > 2 PNG filters (see RFC 2083) get applied and the first byte of each pixelrow defines +// the prediction algorithm used for all pixels of this row. +const ( + PNGNone = 0x00 + PNGSub = 0x01 + PNGUp = 0x02 + PNGAverage = 0x03 + PNGPaeth = 0x04 +) + +type flate struct { + baseFilter +} + +// Encode implements encoding for a Flate filter. +func (f flate) Encode(r io.Reader) (io.Reader, error) { + + log.Trace.Println("EncodeFlate begin") + + // TODO Optional decode parameters may need predictor preprocessing. + + var b bytes.Buffer + w := zlib.NewWriter(&b) + defer w.Close() + + written, err := io.Copy(w, r) + if err != nil { + return nil, err + } + log.Trace.Printf("EncodeFlate end: %d bytes written\n", written) + + return &b, nil +} + +// Decode implements decoding for a Flate filter. +func (f flate) Decode(r io.Reader) (io.Reader, error) { + + log.Trace.Println("DecodeFlate begin") + + rc, err := zlib.NewReader(r) + if err != nil { + return nil, err + } + defer rc.Close() + + // Optional decode parameters need postprocessing. + return f.decodePostProcess(rc) +} + +func passThru(rin io.Reader) (*bytes.Buffer, error) { + var b bytes.Buffer + _, err := io.Copy(&b, rin) + return &b, err +} + +func intMemberOf(i int, list []int) bool { + for _, v := range list { + if i == v { + return true + } + } + return false +} + +// Each prediction value implies (a) certain row filter(s). +func validateRowFilter(f, p int) error { + + switch p { + + case PredictorNone: + if !intMemberOf(f, []int{PNGNone, PNGSub, PNGUp, PNGAverage, PNGPaeth}) { + return errors.Errorf("pdfcpu: validateRowFilter: PredictorOptimum, unexpected row filter #%02x", f) + } + // if f != PNGNone { + // return errors.Errorf("validateRowFilter: expected row filter #%02x, got: #%02x", PNGNone, f) + // } + + case PredictorSub: + if f != PNGSub { + return errors.Errorf("pdfcpu: validateRowFilter: expected row filter #%02x, got: #%02x", PNGSub, f) + } + + case PredictorUp: + if f != PNGUp { + return errors.Errorf("pdfcpu: validateRowFilter: expected row filter #%02x, got: #%02x", PNGUp, f) + } + + case PredictorAverage: + if f != PNGAverage { + return errors.Errorf("pdfcpu: validateRowFilter: expected row filter #%02x, got: #%02x", PNGAverage, f) + } + + case PredictorPaeth: + if f != PNGPaeth { + return errors.Errorf("pdfcpu: validateRowFilter: expected row filter #%02x, got: #%02x", PNGPaeth, f) + } + + case PredictorOptimum: + if !intMemberOf(f, []int{PNGNone, PNGSub, PNGUp, PNGAverage, PNGPaeth}) { + return errors.Errorf("pdfcpu: validateRowFilter: PredictorOptimum, unexpected row filter #%02x", f) + } + + default: + return errors.Errorf("pdfcpu: validateRowFilter: unexpected predictor #%02x", p) + + } + + return nil +} + +func applyHorDiff(row []byte, colors int) ([]byte, error) { + // This works for 8 bits per color only. + for i := 1; i < len(row)/colors; i++ { + for j := 0; j < colors; j++ { + row[i*colors+j] += row[(i-1)*colors+j] + } + } + return row, nil +} + +func processRow(pr, cr []byte, p, colors, bytesPerPixel int) ([]byte, error) { + + //fmt.Printf("pr(%v) =\n%s\n", &pr, hex.Dump(pr)) + //fmt.Printf("cr(%v) =\n%s\n", &cr, hex.Dump(cr)) + + if p == PredictorTIFF { + return applyHorDiff(cr, colors) + } + + // Apply the filter. + cdat := cr[1:] + pdat := pr[1:] + + // Get row filter from 1st byte + f := int(cr[0]) + + // The value of Predictor supplied by the decoding filter need not match the value + // used when the data was encoded if they are both greater than or equal to 10. + + switch f { + + case PNGNone: + // No operation. + + case PNGSub: + for i := bytesPerPixel; i < len(cdat); i++ { + cdat[i] += cdat[i-bytesPerPixel] + } + + case PNGUp: + for i, p := range pdat { + cdat[i] += p + } + + case PNGAverage: + // The average of the two neighboring pixels (left and above). + // Raw(x) - floor((Raw(x-bpp)+Prior(x))/2) + for i := 0; i < bytesPerPixel; i++ { + cdat[i] += pdat[i] / 2 + } + for i := bytesPerPixel; i < len(cdat); i++ { + cdat[i] += uint8((int(cdat[i-bytesPerPixel]) + int(pdat[i])) / 2) + } + + case PNGPaeth: + filterPaeth(cdat, pdat, bytesPerPixel) + + } + + return cdat, nil +} + +func (f flate) parameters() (colors, bpc, columns int, err error) { + + // Colors, int + // The number of interleaved colour components per sample. + // Valid values are 1 to 4 (PDF 1.0) and 1 or greater (PDF 1.3). Default value: 1. + // Used by PredictorTIFF only. + colors, found := f.parms["Colors"] + if !found { + colors = 1 + } else if colors == 0 { + return 0, 0, 0, errors.Errorf("pdfcpu: filter FlateDecode: \"Colors\" must be > 0") + } + + // BitsPerComponent, int + // The number of bits used to represent each colour component in a sample. + // Valid values are 1, 2, 4, 8, and (PDF 1.5) 16. Default value: 8. + // Used by PredictorTIFF only. + bpc, found = f.parms["BitsPerComponent"] + if !found { + bpc = 8 + } else if !intMemberOf(bpc, []int{1, 2, 4, 8, 16}) { + return 0, 0, 0, errors.Errorf("pdfcpu: filter FlateDecode: Unexpected \"BitsPerComponent\": %d", bpc) + } else if bpc != 8 { + return 0, 0, 0, errors.New("pdfcpu: filter FlateDecode: \"BitsPerComponent\" must be 8") + } + + // Columns, int + // The number of samples in each row. Default value: 1. + columns, found = f.parms["Columns"] + if !found { + columns = 1 + } + + return colors, bpc, columns, nil +} + +// decodePostProcess +func (f flate) decodePostProcess(r io.Reader) (io.Reader, error) { + + predictor, found := f.parms["Predictor"] + if !found || predictor == PredictorNo { + return passThru(r) + } + + if !intMemberOf( + predictor, + []int{PredictorTIFF, + PredictorNone, + PredictorSub, + PredictorUp, + PredictorAverage, + PredictorPaeth, + PredictorOptimum, + }) { + return nil, errors.Errorf("pdfcpu: filter FlateDecode: undefined \"Predictor\" %d", predictor) + } + + colors, bpc, columns, err := f.parameters() + if err != nil { + return nil, err + } + + bytesPerPixel := (bpc*colors + 7) / 8 + + rowSize := bpc * colors * columns / 8 + if predictor != PredictorTIFF { + // PNG prediction uses a row filter byte prefixing the pixelbytes of a row. + rowSize++ + } + + // cr and pr are the bytes for the current and previous row. + cr := make([]byte, rowSize) + pr := make([]byte, rowSize) + + // Output buffer + var b bytes.Buffer + + for { + + // Read decompressed bytes for one pixel row. + n, err := io.ReadFull(r, cr) + if err != nil { + if err != io.EOF { + return nil, err + } + // eof + if n == 0 { + break + } + } + + if n != rowSize { + return nil, errors.Errorf("pdfcpu: filter FlateDecode: read error, expected %d bytes, got: %d", rowSize, n) + } + + d, err1 := processRow(pr, cr, predictor, colors, bytesPerPixel) + if err1 != nil { + return nil, err1 + } + + _, err1 = b.Write(d) + if err1 != nil { + return nil, err1 + } + + if err == io.EOF { + break + } + + // Swap byte slices. + pr, cr = cr, pr + } + + if b.Len()%(bpc*colors*columns/8) > 0 { + log.Info.Printf("failed postprocessing: %d %d\n", b.Len(), rowSize) + return nil, errors.New("pdfcpu: filter FlateDecode: postprocessing failed") + } + + return &b, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/lzwDecode.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/lzwDecode.go new file mode 100644 index 0000000..74fb5ba --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/lzwDecode.go @@ -0,0 +1,82 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filter + +import ( + "bytes" + "io" + + "github.com/hhrutter/lzw" + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +type lzwDecode struct { + baseFilter +} + +// Encode implements encoding for an LZWDecode filter. +func (f lzwDecode) Encode(r io.Reader) (io.Reader, error) { + + log.Trace.Println("EncodeLZW begin") + + var b bytes.Buffer + + ec, ok := f.parms["EarlyChange"] + if !ok { + ec = 1 + } + + wc := lzw.NewWriter(&b, ec == 1) + defer wc.Close() + + written, err := io.Copy(wc, r) + if err != nil { + return nil, err + } + log.Trace.Printf("EncodeLZW end: %d bytes written\n", written) + + return &b, nil +} + +// Decode implements decoding for an LZWDecode filter. +func (f lzwDecode) Decode(r io.Reader) (io.Reader, error) { + + log.Trace.Println("DecodeLZW begin") + + p, found := f.parms["Predictor"] + if found && p > 1 { + return nil, errors.Errorf("DecodeLZW: unsupported predictor %d", p) + } + + ec, ok := f.parms["EarlyChange"] + if !ok { + ec = 1 + } + + rc := lzw.NewReader(r, ec == 1) + defer rc.Close() + + var b bytes.Buffer + written, err := io.Copy(&b, rc) + if err != nil { + return nil, err + } + log.Trace.Printf("DecodeLZW: decoded %d bytes.\n", written) + + return &b, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/paeth.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/paeth.go new file mode 100644 index 0000000..c022332 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/paeth.go @@ -0,0 +1,75 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The code to compute Paeth is borrowed from image/png in the stdlib because it is internal over there to the png reader. +// The PNG Paeth filter is documented here: www.w3.org/TR/PNG-Filters.html + +package filter + +// intSize is either 32 or 64. +// Disabled intSize 64 for govet. +const intSize = 32 //<< (^uint(0) >> 63) + +func abs(x int) int { + // m := -1 if x < 0. m := 0 otherwise. + m := x >> (intSize - 1) + + // In two's complement representation, the negative number + // of any number (except the smallest one) can be computed + // by flipping all the bits and add 1. This is faster than + // code with a branch. + // See Hacker's Delight, section 2-4. + return (x ^ m) - m +} + +// paeth implements the Paeth filter function, as per the PNG specification. +func paeth(a, b, c uint8) uint8 { + // This is an optimized version of the sample code in the PNG spec. + // For example, the sample code starts with: + // p := int(a) + int(b) - int(c) + // pa := abs(p - int(a)) + // but the optimized form uses fewer arithmetic operations: + // pa := int(b) - int(c) + // pa = abs(pa) + pc := int(c) + pa := int(b) - pc + pb := int(a) - pc + pc = abs(pa + pb) + pa = abs(pa) + pb = abs(pb) + if pa <= pb && pa <= pc { + return a + } else if pb <= pc { + return b + } + return c +} + +// filterPaeth applies the Paeth filter to the cdat slice. +// cdat is the current row's data, pdat is the previous row's data. +func filterPaeth(cdat, pdat []byte, bytesPerPixel int) { + var a, b, c, pa, pb, pc int + for i := 0; i < bytesPerPixel; i++ { + a, c = 0, 0 + for j := i; j < len(cdat); j += bytesPerPixel { + b = int(pdat[j]) + pa = b - c + pb = a - c + pc = abs(pa + pb) + pa = abs(pa) + pb = abs(pb) + if pa <= pb && pa <= pc { + // No-op. + } else if pb <= pc { + a = b + } else { + a = c + } + a += int(cdat[j]) + a &= 0xff + cdat[j] = uint8(a) + c = b + } + } +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/runLengthDecode.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/runLengthDecode.go new file mode 100644 index 0000000..2020747 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/filter/runLengthDecode.go @@ -0,0 +1,141 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package filter + +import ( + "bytes" + "io" + "io/ioutil" +) + +type runLengthDecode struct { + baseFilter +} + +func (f runLengthDecode) decode(w io.ByteWriter, src []byte) { + + for i := 0; i < len(src); { + b := src[i] + if b == 0x80 { + // eod + break + } + i++ + if b < 0x80 { + c := int(b) + 1 + for j := 0; j < c; j++ { + w.WriteByte(src[i]) + i++ + } + continue + } + c := 257 - int(b) + for j := 0; j < c; j++ { + w.WriteByte(src[i]) + } + i++ + } + + return +} + +func (f runLengthDecode) encode(w io.ByteWriter, src []byte) { + + const maxLen = 0x80 + const eod = 0x80 + + i := 0 + b := src[i] + start := i + + for { + + // Detect constant run eg. 0x1414141414141414 + for i < len(src) && src[i] == b && (i-start < maxLen) { + i++ + } + c := i - start + if c > 1 { + // Write constant run with length=c + w.WriteByte(byte(257 - c)) + w.WriteByte(b) + if i == len(src) { + w.WriteByte(0x80) + return + } + b = src[i] + start = i + continue + } + + // Detect variable run eg. 0x20FFD023335BCC12 + for i < len(src) && src[i] != b && (i-start < maxLen) { + b = src[i] + i++ + } + if i == len(src) || i-start == maxLen { + c = i - start + w.WriteByte(byte(c - 1)) + for j := 0; j < c; j++ { + w.WriteByte(src[start+j]) + } + if i == len(src) { + w.WriteByte(0x80) + return + } + } else { + c = i - 1 - start + // Write variable run with length=c + w.WriteByte(byte(c - 1)) + for j := 0; j < c; j++ { + w.WriteByte(src[start+j]) + } + i-- + } + b = src[i] + start = i + } + +} + +// Encode implements encoding for a RunLengthDecode filter. +func (f runLengthDecode) Encode(r io.Reader) (io.Reader, error) { + + p, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + var b bytes.Buffer + f.encode(&b, p) + + return &b, nil +} + +// Decode implements decoding for an RunLengthDecode filter. +func (f runLengthDecode) Decode(r io.Reader) (io.Reader, error) { + + p, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + var b bytes.Buffer + f.decode(&b, p) + + return &b, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/font/install.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/font/install.go new file mode 100644 index 0000000..8546351 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/font/install.go @@ -0,0 +1,1022 @@ +/* +Copyright 2019 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package font provides support for TrueType fonts. +package font + +import ( + "bytes" + "encoding/binary" + "encoding/gob" + "fmt" + "io" + "os" + "path/filepath" + "reflect" + "sort" + "strings" + "unicode/utf16" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +const ( + sfntVersionTrueType = "\x00\x01\x00\x00" + sfntVersionTrueTypeApple = "true" + sfntVersionCFF = "OTTO" + ttfHeadMagicNumber = 0x5F0F3CF5 + ttcTag = "ttcf" +) + +type ttf struct { + PostscriptName string // name: NameID 6 + Protected bool // OS/2: fsType + UnitsPerEm int // head: unitsPerEm + Ascent int // OS/2: sTypoAscender + Descent int // OS/2: sTypoDescender + CapHeight int // OS/2: sCapHeight + FirstChar uint16 // OS/2: fsFirstCharIndex + LastChar uint16 // OS/2: fsLastCharIndex + UnicodeRange [4]uint32 // OS/2: Unicode Character Range + LLx, LLy, URx, URy float64 // head: xMin, yMin, xMax, yMax (fontbox) + ItalicAngle float64 // post: italicAngle + FixedPitch bool // post: isFixedPitch + Bold bool // OS/2: usWeightClass == 7 + HorMetricsCount int // hhea: numOfLongHorMetrics + GlyphCount int // maxp: numGlyphs + GlyphWidths []int // hmtx: fd.HorMetricsCount.advanceWidth + Chars map[uint32]uint16 // cmap: Unicode character to glyph index + ToUnicode map[uint16]uint32 // map glyph index to unicode character + Planes map[int]bool // used Unicode planes + FontFile []byte +} + +func (fd ttf) String() string { + return fmt.Sprintf(` + PostscriptName = %s + Protected = %t + UnitsPerEm = %d + Ascent = %d + Descent = %d + CapHeight = %d + FirstChar = %d + LastChar = %d +FontBoundingBox = (%.2f, %.2f, %.2f, %.2f) + ItalicAngle = %.2f + FixedPitch = %t + Bold = %t +HorMetricsCount = %d + GlyphCount = %d`, + fd.PostscriptName, + fd.Protected, + fd.UnitsPerEm, + fd.Ascent, + fd.Descent, + fd.CapHeight, + fd.FirstChar, + fd.LastChar, + fd.LLx, fd.LLy, fd.URx, fd.URy, + fd.ItalicAngle, + fd.FixedPitch, + fd.Bold, + fd.HorMetricsCount, + fd.GlyphCount, + ) +} + +func (fd ttf) toPDFGlyphSpace(i int) int { + return i * 1000 / fd.UnitsPerEm +} + +type myUint32 []uint32 + +func (f myUint32) Len() int { + return len(f) +} + +func (f myUint32) Less(i, j int) bool { + return f[i] < f[j] +} + +func (f myUint32) Swap(i, j int) { + f[i], f[j] = f[j], f[i] +} + +func (fd ttf) PrintChars() string { + var min = uint16(0xFFFF) + var max uint16 + var sb strings.Builder + sb.WriteByte(0x0a) + + keys := make(myUint32, 0, len(fd.Chars)) + for k := range fd.Chars { + keys = append(keys, k) + } + sort.Sort(keys) + + for _, c := range keys { + g := fd.Chars[c] + if g > max { + max = g + } + if g < min { + min = g + } + sb.WriteString(fmt.Sprintf("#%x -> #%x(%d)\n", c, g, g)) + } + fmt.Printf("using glyphs[%08x,%08x] [%d,%d]\n", min, max, min, max) + fmt.Printf("using glyphs #%x - #%x (%d-%d)\n", min, max, min, max) + return sb.String() +} + +type table struct { + chksum uint32 + off uint32 + size uint32 + padded uint32 + data []byte +} + +func (t table) uint16(off int) uint16 { + return binary.BigEndian.Uint16(t.data[off:]) +} + +func (t table) int16(off int) int16 { + return int16(t.uint16(off)) +} + +func (t table) uint32(off int) uint32 { + return binary.BigEndian.Uint32(t.data[off:]) +} + +func (t table) fixed32(off int) float64 { + return float64(t.uint32(off)) / 65536.0 +} + +func (t table) parseFontHeaderTable(fd *ttf) error { + // table "head" + magic := t.uint32(12) + if magic != ttfHeadMagicNumber { + return fmt.Errorf("parseHead: wrong magic number") + } + + unitsPerEm := t.uint16(18) + //fmt.Printf("unitsPerEm: %d\n", unitsPerEm) + fd.UnitsPerEm = int(unitsPerEm) + + llx := t.int16(36) + //fmt.Printf("llx: %d\n", llx) + fd.LLx = float64(fd.toPDFGlyphSpace(int(llx))) + + lly := t.int16(38) + //fmt.Printf("lly: %d\n", lly) + fd.LLy = float64(fd.toPDFGlyphSpace(int(lly))) + + urx := t.int16(40) + //fmt.Printf("urx: %d\n", urx) + fd.URx = float64(fd.toPDFGlyphSpace(int(urx))) + + ury := t.int16(42) + //fmt.Printf("ury: %d\n", ury) + fd.URy = float64(fd.toPDFGlyphSpace(int(ury))) + + return nil +} + +func uint16ToBigEndianBytes(i uint16) []byte { + b := make([]byte, 2) + binary.BigEndian.PutUint16(b, i) + return b +} + +func uint32ToBigEndianBytes(i uint32) []byte { + b := make([]byte, 4) + binary.BigEndian.PutUint32(b, i) + return b +} + +func utf16BEToString(bb []byte) string { + buf := make([]uint16, len(bb)/2) + for i := 0; i < len(buf); i++ { + buf[i] = binary.BigEndian.Uint16(bb[2*i:]) + } + return string(utf16.Decode(buf)) +} + +func (t table) parsePostScriptTable(fd *ttf) error { + // table "post" + italicAngle := t.fixed32(4) + //fmt.Printf("italicAngle: %2.2f\n", italicAngle) + fd.ItalicAngle = italicAngle + + isFixedPitch := t.uint16(16) + //fmt.Printf("isFixedPitch: %t\n", isFixedPitch != 0) + fd.FixedPitch = isFixedPitch != 0 + + return nil +} + +func printUnicodeRange(off int, r uint32) { + for i := 0; i < 64; i++ { + if r&1 > 0 { + fmt.Printf("bit %d: on\n", off+i) + } + r >>= 1 + } +} + +func (t table) parseWindowsMetricsTable(fd *ttf) error { + // table "OS/2" + version := t.uint16(0) + fsType := t.uint16(8) + fd.Protected = fsType&2 > 0 + //fmt.Printf("protected: %t\n", fd.Protected) + + uniCodeRange1 := t.uint32(42) + //fmt.Printf("uniCodeRange1: %032b\n", uniCodeRange1) + fd.UnicodeRange[0] = uniCodeRange1 + + uniCodeRange2 := t.uint32(46) + //fmt.Printf("uniCodeRange2: %032b\n", uniCodeRange2) + fd.UnicodeRange[1] = uniCodeRange2 + + uniCodeRange3 := t.uint32(50) + //fmt.Printf("uniCodeRange3: %032b\n", uniCodeRange3) + fd.UnicodeRange[2] = uniCodeRange3 + + uniCodeRange4 := t.uint32(54) + //fmt.Printf("uniCodeRange4: %032b\n", uniCodeRange4) + fd.UnicodeRange[3] = uniCodeRange4 + + // printUnicodeRange(0, uniCodeRange1) + // printUnicodeRange(32, uniCodeRange2) + // printUnicodeRange(64, uniCodeRange3) + // printUnicodeRange(96, uniCodeRange4) + + sTypoAscender := t.int16(68) + fd.Ascent = fd.toPDFGlyphSpace(int(sTypoAscender)) + + sTypoDescender := t.int16(70) + fd.Descent = fd.toPDFGlyphSpace(int(sTypoDescender)) + + // sCapHeight: This field was defined in version 2 of the OS/2 table. + sCapHeight := int16(0) + if version >= 2 { + sCapHeight = t.int16(88) + } + fd.CapHeight = fd.toPDFGlyphSpace(int(sCapHeight)) + + fsSelection := t.uint16(62) + fd.Bold = fsSelection&0x40 > 0 + + fsFirstCharIndex := t.uint16(64) + fd.FirstChar = fsFirstCharIndex + + fsLastCharIndex := t.uint16(66) + fd.LastChar = fsLastCharIndex + + return nil +} + +func (t table) parseNamingTable(fd *ttf) error { + // table "name" + count := int(t.uint16(2)) + stringOffset := t.uint16(4) + nameID := uint16(0) + baseOff := 6 + for i := 0; i < count; i++ { + recOff := baseOff + i*12 + pf := t.uint16(recOff) + enc := t.uint16(recOff + 2) + lang := t.uint16(recOff + 4) + nameID = t.uint16(recOff + 6) + l := t.uint16(recOff + 8) + o := t.uint16(recOff + 10) + soff := stringOffset + o + s := t.data[soff : soff+l] + if nameID == 6 { + if pf == 3 && enc == 1 && lang == 0x0409 { + fd.PostscriptName = utf16BEToString(s) + return nil + } + if pf == 1 && enc == 0 && lang == 0 { + fd.PostscriptName = string(s) + return nil + } + } + } + + return errors.New("pdfcpu: unable to identify postscript name") +} + +func (t table) parseHorizontalHeaderTable(fd *ttf) error { + // table "hhea" + ascent := t.int16(4) + //fmt.Printf("ascent: %d\n", ascent) + if fd.Ascent == 0 { + fd.Ascent = fd.toPDFGlyphSpace(int(ascent)) + } + + descent := t.int16(6) + //fmt.Printf("descent: %d\n", descent) + if fd.Descent == 0 { + fd.Descent = fd.toPDFGlyphSpace(int(descent)) + } + + lineGap := t.int16(8) + //fmt.Printf("lineGap: %d\n", lineGap) + if fd.CapHeight == 0 { + fd.CapHeight = fd.toPDFGlyphSpace(int(lineGap)) + } + + //advanceWidthMax := t.uint16(10) + //fmt.Printf("advanceWidthMax: %d\n", advanceWidthMax) + + //minLeftSideBearing := t.int16(12) + //fmt.Printf("minLeftSideBearing: %d\n", minLeftSideBearing) + + //minRightSideBearing := t.int16(14) + //fmt.Printf("minRightSideBearing: %d\n", minRightSideBearing) + + //xMaxExtent := t.int16(16) + //fmt.Printf("xMaxExtent: %d\n", xMaxExtent) + + numOfLongHorMetrics := t.uint16(34) + //fmt.Printf("numOfLongHorMetrics: %d\n", numOfLongHorMetrics) + fd.HorMetricsCount = int(numOfLongHorMetrics) + + return nil +} + +func (t table) parseMaximumProfile(fd *ttf) error { + // table "maxp" + numGlyphs := t.uint16(4) + fd.GlyphCount = int(numGlyphs) + return nil +} + +func (t table) parseHorizontalMetricsTable(fd *ttf) error { + // table "hmtx" + fd.GlyphWidths = make([]int, fd.GlyphCount) + + for i := 0; i < int(fd.HorMetricsCount); i++ { + fd.GlyphWidths[i] = fd.toPDFGlyphSpace(int(t.uint16(i * 4))) + } + + for i := fd.HorMetricsCount; i < fd.GlyphCount; i++ { + fd.GlyphWidths[i] = fd.GlyphWidths[fd.HorMetricsCount-1] + } + + return nil +} + +func (t table) parseCMapFormat4(fd *ttf) error { + fd.Planes[0] = true + segCount := int(t.uint16(6) / 2) + endOff := 14 + startOff := endOff + 2*segCount + 2 + deltaOff := startOff + 2*segCount + rangeOff := deltaOff + 2*segCount + + count := 0 + for i := 0; i < segCount; i++ { + sc := t.uint16(startOff + i*2) + startCode := uint32(sc) + if fd.FirstChar == 0 { + fd.FirstChar = sc + } + ec := t.uint16(endOff + i*2) + endCode := uint32(ec) + if fd.LastChar == 0 { + fd.LastChar = ec + } + idDelta := uint32(t.uint16(deltaOff + i*2)) + idRangeOff := int(t.uint16(rangeOff + i*2)) + v := uint16(0) + for c, j := startCode, 0; c <= endCode && c != 0xFFFF; c++ { + if idRangeOff > 0 { + v = t.uint16(rangeOff + i*2 + idRangeOff + j*2) + } else { + v = uint16(c + idDelta) + } + if gi := v; gi > 0 { + fd.Chars[c] = gi + fd.ToUnicode[gi] = c + count++ + } + j++ + } + } + return nil +} + +func (t table) parseCMapFormat12(fd *ttf) error { + numGroups := int(t.uint32(12)) + off := 16 + count := 0 + var ( + lowestStartCode uint32 + prevCode uint32 + ) + for i := 0; i < numGroups; i++ { + base := off + i*12 + startCode := t.uint32(base) + if lowestStartCode == 0 { + lowestStartCode = startCode + fd.Planes[int(lowestStartCode/0x10000)] = true + } + if startCode/0x10000 != prevCode/0x10000 { + fd.Planes[int(startCode/0x10000)] = true + } + endCode := t.uint32(base + 4) + if startCode != endCode { + if startCode/0x10000 != endCode/0x10000 { + fd.Planes[int(endCode/0x10000)] = true + } + } + prevCode = endCode + startGlyphID := uint16(t.uint32(base + 8)) + for c, gi := startCode, startGlyphID; c <= endCode; c++ { + fd.Chars[c] = gi + fd.ToUnicode[gi] = c + gi++ + count++ + } + } + return nil +} + +func (t table) parseCharToGlyphMappingTable(fd *ttf) error { + // table "cmap" + + fd.Chars = map[uint32]uint16{} + fd.ToUnicode = map[uint16]uint32{} + fd.Planes = map[int]bool{} + tableCount := t.uint16(2) + baseOff := 4 + var pf, enc, f uint16 + m := map[string]table{} + + for i := 0; i < int(tableCount); i++ { + off := baseOff + i*8 + pf = t.uint16(off) + enc = t.uint16(off + 2) + o := t.uint32(off + 4) + f = t.uint16(int(o)) + l := uint32(t.uint16(int(o) + 2)) + if f >= 8 { + l = t.uint32(int(o) + 4) + } + b := t.data[o : o+l] + t1 := table{off: o, size: uint32(l), data: b} + k := fmt.Sprintf("p%02d.e%02d.f%02d", pf, enc, f) + m[k] = t1 + } + + if t, ok := m["p00.e10.f12"]; ok { + return t.parseCMapFormat12(fd) + } + if t, ok := m["p00.e04.f12"]; ok { + return t.parseCMapFormat12(fd) + } + if t, ok := m["p03.e10.f12"]; ok { + return t.parseCMapFormat12(fd) + } + if t, ok := m["p00.e03.f04"]; ok { + return t.parseCMapFormat4(fd) + } + if t, ok := m["p03.e01.f04"]; ok { + return t.parseCMapFormat4(fd) + } + + return fmt.Errorf("pdfcpu: unsupported cmap table") +} + +func calcTableChecksum(tag string, b []byte) uint32 { + sum := uint32(0) + c := (len(b) + 3) / 4 + for i := 0; i < c; i++ { + if tag == "head" && i == 2 { + continue + } + sum += binary.BigEndian.Uint32(b[i*4:]) + } + return sum +} + +func getNext32BitAlignedLength(i uint32) uint32 { + if i%4 > 0 { + return i + (4 - i%4) + } + return i +} + +func headerAndTables(fn string, r io.ReaderAt, baseOff int64) ([]byte, map[string]*table, error) { + header := make([]byte, 12) + n, err := r.ReadAt(header, baseOff) + if err != nil { + return nil, nil, err + } + if n != 12 { + return nil, nil, fmt.Errorf("pdfcpu: corrupt ttf file: %s", fn) + } + + st := string(header[:4]) + + if st == sfntVersionCFF { + return nil, nil, fmt.Errorf("pdfcpu: %s is based on OpenType CFF and unsupported at the moment :(", fn) + } + + if st != sfntVersionTrueType && st != sfntVersionTrueTypeApple { + return nil, nil, fmt.Errorf("pdfcpu: unrecognized font format: %s", fn) + } + + c := int(binary.BigEndian.Uint16(header[4:])) + + b := make([]byte, c*16) + n, err = r.ReadAt(b, baseOff+12) + if err != nil { + return nil, nil, err + } + if n != c*16 { + return nil, nil, fmt.Errorf("pdfcpu: corrupt ttf file: %s", fn) + } + + byteCount := uint32(12) + tables := map[string]*table{} + + for j := 0; j < c; j++ { + off := j * 16 + b1 := b[off : off+16] + tag := string(b1[:4]) + chk := binary.BigEndian.Uint32(b1[4:]) + o := binary.BigEndian.Uint32(b1[8:]) + l := binary.BigEndian.Uint32(b1[12:]) + ll := getNext32BitAlignedLength(l) + byteCount += ll + t := make([]byte, ll) + n, err = r.ReadAt(t, int64(o)) + if err != nil { + return nil, nil, err + } + if n != int(ll) { + return nil, nil, fmt.Errorf("pdfcpu: corrupt table: %s", tag) + } + sum := calcTableChecksum(tag, t) + if sum != chk { + fmt.Printf("pdfcpu: fixing table<%s> checksum error; want:%d got:%d\n", tag, chk, sum) + chk = sum + } + tables[tag] = &table{chksum: chk, off: o, size: l, padded: ll, data: t} + } + + return header, tables, nil +} + +func parse(tags map[string]*table, tag string, fd *ttf) error { + t, found := tags[tag] + if !found { + // OS/2 is optional for True Type fonts. + if tag == "OS/2" { + return nil + } + return fmt.Errorf("pdfcpu: tag: %s unavailable", tag) + } + if t.data == nil { + return fmt.Errorf("pdfcpu: tag: %s no data", tag) + } + + var err error + + switch tag { + case "head": + err = t.parseFontHeaderTable(fd) + case "OS/2": + err = t.parseWindowsMetricsTable(fd) + case "post": + err = t.parsePostScriptTable(fd) + case "name": + err = t.parseNamingTable(fd) + case "hhea": + err = t.parseHorizontalHeaderTable(fd) + case "maxp": + err = t.parseMaximumProfile(fd) + case "hmtx": + err = t.parseHorizontalMetricsTable(fd) + case "cmap": + err = t.parseCharToGlyphMappingTable(fd) + } + + return err +} + +func writeGob(fileName string, fd ttf) error { + f, err := os.Create(fileName) + if err != nil { + return err + } + defer f.Close() + enc := gob.NewEncoder(f) + return enc.Encode(fd) +} + +func readGob(fileName string, fd *ttf) error { + f, err := os.Open(fileName) + if err != nil { + return err + } + defer f.Close() + dec := gob.NewDecoder(f) + return dec.Decode(fd) +} + +func installTrueTypeRep(fontDir, fontName string, header []byte, tables map[string]*table) error { + fd := ttf{} + for _, v := range []string{"head", "OS/2", "post", "name", "hhea", "maxp", "hmtx", "cmap"} { + if err := parse(tables, v, &fd); err != nil { + return err + } + } + + bb, err := createTTF(header, tables) + if err != nil { + return err + } + fd.FontFile = bb + + log.CLI.Println(fd.PostscriptName) + gobName := filepath.Join(fontDir, fd.PostscriptName+".gob") + + // Write the populated ttf struct as gob. + if err := writeGob(gobName, fd); err != nil { + return err + } + + // Read gob and double check integrity. + fdNew := ttf{} + if err := readGob(gobName, &fdNew); err != nil { + return err + } + + if !reflect.DeepEqual(fd, fdNew) { + return errors.Errorf("pdfcpu: %s can't be installed", fontName) + } + + return nil +} + +// InstallTrueTypeCollection saves an internal representation of all fonts +// contained in a TrueType collection to the pdfcpu config dir. +func InstallTrueTypeCollection(fontDir, fn string) error { + f, err := os.Open(fn) + if err != nil { + return err + } + defer f.Close() + + b := make([]byte, 12) + n, err := f.Read(b) + if err != nil { + return err + } + if n != 12 { + return fmt.Errorf("pdfcpu: corrupt ttc file: %s", fn) + } + + if string(b[:4]) != ttcTag { + return fmt.Errorf("pdfcpu: corrupt ttc file: %s", fn) + } + + c := int(binary.BigEndian.Uint32(b[8:])) + + b = make([]byte, c*4) + n, err = f.ReadAt(b, 12) + if err != nil { + return err + } + if n != c*4 { + return fmt.Errorf("pdfcpu: corrupt ttc file: %s", fn) + } + + // Process contained fonts. + for i := 0; i < c; i++ { + off := int64(binary.BigEndian.Uint32(b[i*4:])) + header, tables, err := headerAndTables(fn, f, off) + if err != nil { + return err + } + if err := installTrueTypeRep(fontDir, fn, header, tables); err != nil { + return err + } + } + + return nil +} + +// InstallTrueTypeFont saves an internal representation of TrueType font fontName to the pdfcpu config dir. +func InstallTrueTypeFont(fontDir, fontName string) error { + f, err := os.Open(fontName) + if err != nil { + return err + } + defer f.Close() + + header, tables, err := headerAndTables(fontName, f, 0) + if err != nil { + return err + } + return installTrueTypeRep(fontDir, fontName, header, tables) +} + +func ttfTables(tableCount int, bb []byte) (map[string]*table, error) { + tables := map[string]*table{} + b := bb[12:] + for j := 0; j < tableCount; j++ { + off := j * 16 + b1 := b[off : off+16] + tag := string(b1[:4]) + chksum := binary.BigEndian.Uint32(b1[4:]) + o := binary.BigEndian.Uint32(b1[8:]) + l := binary.BigEndian.Uint32(b1[12:]) + ll := getNext32BitAlignedLength(l) + t := append([]byte(nil), bb[o:o+ll]...) + tables[tag] = &table{chksum: chksum, off: o, size: l, padded: ll, data: t} + } + return tables, nil +} + +func glyfOffset(loca *table, gid, indexToLocFormat int) int { + if indexToLocFormat == 0 { + // short offsets + return 2 * int(loca.uint16(2*gid)) + } + // 1 .. long offsets + return int(loca.uint32(4 * gid)) +} + +func writeGlyfOffset(buf *bytes.Buffer, off, indexToLocFormat int) { + var bb []byte + if indexToLocFormat == 0 { + // 0 .. short offsets + bb = uint16ToBigEndianBytes(uint16(off / 2)) + } else { + // 1 .. long offsets + bb = uint32ToBigEndianBytes(uint32(off)) + } + buf.Write(bb) +} + +func pad(bb []byte) []byte { + i := len(bb) % 4 + if i == 0 { + return bb + } + for j := 0; j < 4-i; j++ { + bb = append(bb, 0x00) + } + return bb +} + +func glyphOffsets(gid int, locaFull, glyfsFull *table, numGlyphs, indexToLocFormat int) (int, int) { + offFrom := glyfOffset(locaFull, gid, indexToLocFormat) + var offThru int + if gid == numGlyphs { + offThru = int(glyfsFull.padded) + } else { + offThru = glyfOffset(locaFull, gid+1, indexToLocFormat) + } + return offFrom, offThru +} + +func resolveCompoundGlyph(fontName string, bb []byte, usedGIDs map[uint16]bool, + locaFull, glyfsFull *table, numGlyphs, indexToLocFormat int) error { + last := false + for off := 10; !last; { + flags := binary.BigEndian.Uint16(bb[off:]) + last = flags&0x20 == 0 + wordArgs := flags&0x01 > 0 + + gid := binary.BigEndian.Uint16(bb[off+2:]) + + // Position behind arguments. + off += 6 + if wordArgs { + off += 2 + } + + // Position behind transform. + if flags&0x08 > 0 { + off += 2 + } else if flags&0x40 > 0 { + off += 4 + } else if flags&0x80 > 0 { + off += 8 + } + + if _, ok := usedGIDs[gid]; ok { + // duplicate + continue + } + + offFrom, offThru := glyphOffsets(int(gid), locaFull, glyfsFull, numGlyphs, indexToLocFormat) + if offThru < offFrom { + return errors.Errorf("pdfcpu: illegal glyfOffset for font: %s", fontName) + } + if offFrom == offThru { + // not available + continue + } + + usedGIDs[gid] = true + + cbb := glyfsFull.data[offFrom:offThru] + if cbb[0]&0x80 == 0 { + // simple + continue + } + + if err := resolveCompoundGlyph(fontName, cbb, usedGIDs, locaFull, glyfsFull, numGlyphs, indexToLocFormat); err != nil { + return err + } + } + return nil +} + +func resolveCompoundGlyphs(fontName string, usedGIDs map[uint16]bool, locaFull, glyfsFull *table, numGlyphs, indexToLocFormat int) error { + gids := make([]uint16, len(usedGIDs)) + for k := range usedGIDs { + gids = append(gids, k) + } + for _, gid := range gids { + offFrom, offThru := glyphOffsets(int(gid), locaFull, glyfsFull, numGlyphs, indexToLocFormat) + if offThru < offFrom { + return errors.Errorf("pdfcpu: illegal glyfOffset for font: %s", fontName) + } + if offFrom == offThru { + continue + } + bb := glyfsFull.data[offFrom:offThru] + if bb[0]&0x80 == 0 { + // simple + continue + } + if err := resolveCompoundGlyph(fontName, bb, usedGIDs, locaFull, glyfsFull, numGlyphs, indexToLocFormat); err != nil { + return err + } + } + return nil +} + +func glyfAndLoca(fontName string, tables map[string]*table, usedGIDs map[uint16]bool) error { + head, ok := tables["head"] + if !ok { + return errors.Errorf("pdfcpu: missing \"head\" table for font: %s", fontName) + } + + maxp, ok := tables["maxp"] + if !ok { + return errors.Errorf("pdfcpu: missing \"maxp\" table for font: %s", fontName) + } + + glyfsFull, ok := tables["glyf"] + if !ok { + return errors.Errorf("pdfcpu: missing \"glyf\" table for font: %s", fontName) + } + + locaFull, ok := tables["loca"] + if !ok { + return errors.Errorf("pdfcpu: missing \"loca\" table for font: %s", fontName) + } + + indexToLocFormat := int(head.uint16(50)) + // 0 .. short offsets + // 1 .. long offsets + numGlyphs := int(maxp.uint16(4)) + + if err := resolveCompoundGlyphs(fontName, usedGIDs, locaFull, glyfsFull, numGlyphs, indexToLocFormat); err != nil { + return err + } + + gids := make([]int, 0, len(usedGIDs)+1) + gids = append(gids, 0) + for gid := range usedGIDs { + gids = append(gids, int(gid)) + } + sort.Ints(gids) + + glyfBytes := []byte{} + var buf bytes.Buffer + off := 0 + firstPendingGID := 0 + + for _, gid := range gids { + offFrom, offThru := glyphOffsets(gid, locaFull, glyfsFull, numGlyphs, indexToLocFormat) + if offThru < offFrom { + return errors.Errorf("pdfcpu: illegal glyfOffset for font: %s", fontName) + } + if offThru != offFrom { + // We have a glyph outline. + for i := 0; i < gid-firstPendingGID; i++ { + writeGlyfOffset(&buf, off, indexToLocFormat) + } + glyfBytes = append(glyfBytes, glyfsFull.data[offFrom:offThru]...) + writeGlyfOffset(&buf, off, indexToLocFormat) + off += offThru - offFrom + firstPendingGID = gid + 1 + } + } + for i := 0; i <= numGlyphs-firstPendingGID; i++ { + writeGlyfOffset(&buf, off, indexToLocFormat) + } + + bb := buf.Bytes() + locaFull.size = uint32(len(bb)) + locaFull.data = pad(bb) + locaFull.padded = uint32(len(locaFull.data)) + + glyfsFull.size = uint32(len(glyfBytes)) + glyfsFull.data = pad(glyfBytes) + glyfsFull.padded = uint32(len(glyfsFull.data)) + + return nil +} + +func createTTF(header []byte, tables map[string]*table) ([]byte, error) { + tags := []string{} + for t := range tables { + tags = append(tags, t) + } + sort.Strings(tags) + + buf := bytes.NewBuffer(header) + off := uint32(len(header) + len(tables)*16) + o := off + for _, tag := range tags { + t := tables[tag] + if _, err := buf.WriteString(tag); err != nil { + return nil, err + } + if tag == "loca" || tag == "glyf" { + t.chksum = calcTableChecksum(tag, t.data) + } + if _, err := buf.Write(uint32ToBigEndianBytes(t.chksum)); err != nil { + return nil, err + } + t.off = o + if _, err := buf.Write(uint32ToBigEndianBytes(t.off)); err != nil { + return nil, err + } + if _, err := buf.Write(uint32ToBigEndianBytes(t.size)); err != nil { + return nil, err + } + o += t.padded + } + + for _, tag := range tags { + t := tables[tag] + n, err := buf.Write(t.data) + if err != nil { + return nil, err + } + if n != len(t.data) || n != int(t.padded) { + return nil, errors.Errorf("pdfcpu: unable to write %s data\n", tag) + } + } + + return buf.Bytes(), nil +} + +// Subset creates a new font file based on usedGIDs. +func Subset(fontName string, usedGIDs map[uint16]bool) ([]byte, error) { + bb, err := Read(fontName) + if err != nil { + return nil, err + } + + header := bb[:12] + tableCount := int(binary.BigEndian.Uint16(header[4:])) + tables, err := ttfTables(tableCount, bb) + if err != nil { + return nil, err + } + + if err := glyfAndLoca(fontName, tables, usedGIDs); err != nil { + return nil, err + } + + return createTTF(header, tables) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/font/metrics.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/font/metrics.go new file mode 100644 index 0000000..45e0b91 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/font/metrics.go @@ -0,0 +1,307 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package font + +import ( + "encoding/gob" + "fmt" + "io/ioutil" + "math" + "os" + "path" + "path/filepath" + "strconv" + "strings" + + "github.com/pdfcpu/pdfcpu/internal/corefont/metrics" + "github.com/pdfcpu/pdfcpu/pkg/types" +) + +// TTFLight represents a TrueType font w/o font file. +type TTFLight struct { + PostscriptName string // name: NameID 6 + Protected bool // OS/2: fsType + UnitsPerEm int // head: unitsPerEm + Ascent int // OS/2: sTypoAscender + Descent int // OS/2: sTypoDescender + CapHeight int // OS/2: sCapHeight + FirstChar uint16 // OS/2: fsFirstCharIndex + LastChar uint16 // OS/2: fsLastCharIndex + UnicodeRange [4]uint32 // OS/2: Unicode Character Range + LLx, LLy, URx, URy float64 // head: xMin, yMin, xMax, yMax (fontbox) + ItalicAngle float64 // post: italicAngle + FixedPitch bool // post: isFixedPitch + Bold bool // OS/2: usWeightClass == 7 + HorMetricsCount int // hhea: numOfLongHorMetrics + GlyphCount int // maxp: numGlyphs + GlyphWidths []int // hmtx: fd.HorMetricsCount.advanceWidth + Chars map[uint32]uint16 // cmap: Unicode character to glyph index + ToUnicode map[uint16]uint32 // map glyph index to unicode character + Planes map[int]bool // used Unicode planes + UsedGIDs map[uint16]bool +} + +func (fd TTFLight) String() string { + return fmt.Sprintf(` + PostscriptName = %s + Protected = %t + UnitsPerEm = %d + Ascent = %d + Descent = %d + CapHeight = %d + FirstChar = %d + LastChar = %d +FontBoundingBox = (%.2f, %.2f, %.2f, %.2f) + ItalicAngle = %.2f + FixedPitch = %t + Bold = %t +HorMetricsCount = %d + GlyphCount = %d +len(GlyphWidths) = %d`, + fd.PostscriptName, + fd.Protected, + fd.UnitsPerEm, + fd.Ascent, + fd.Descent, + fd.CapHeight, + fd.FirstChar, + fd.LastChar, + fd.LLx, fd.LLy, fd.URx, fd.URy, + fd.ItalicAngle, + fd.FixedPitch, + fd.Bold, + fd.HorMetricsCount, + fd.GlyphCount, + len(fd.GlyphWidths), + ) +} + +func (fd TTFLight) supportsUnicodeBlock(bit int) bool { + i := fd.UnicodeRange[bit/32] + i >>= uint32(bit) % 32 + return i&1 > 0 +} + +func (fd TTFLight) isCJK() bool { + // 4E00-9FFF CJK Unified Ideographs + return fd.supportsUnicodeBlock(59) +} + +// UserFontDir is the location for installed TTF or OTF font files. +var UserFontDir string + +// UserFontMetrics represents font metrics for TTF or OTF font files installed into UserFontDir. +var UserFontMetrics = map[string]TTFLight{} + +func load(fileName string, fd *TTFLight) error { + //fmt.Printf("reading gob from: %s\n", fileName) + f, err := os.Open(fileName) + if err != nil { + return err + } + defer f.Close() + dec := gob.NewDecoder(f) + return dec.Decode(fd) +} + +// Read reads in the font file bytes from gob +func Read(fileName string) ([]byte, error) { + fn := filepath.Join(UserFontDir, fileName+".gob") + f, err := os.Open(fn) + if err != nil { + return nil, err + } + defer f.Close() + dec := gob.NewDecoder(f) + ff := &struct{ FontFile []byte }{} + err = dec.Decode(ff) + return ff.FontFile, err +} + +func isSupportedFontFile(filename string) bool { + return strings.HasSuffix(strings.ToLower(filename), ".gob") +} + +// LoadUserFonts loads any installed TTF or OTF font files. +func LoadUserFonts() error { + //fmt.Printf("loading userFonts from %s\n", UserFontDir) + files, err := ioutil.ReadDir(UserFontDir) + if err != nil { + return err + } + for _, f := range files { + if !isSupportedFontFile(f.Name()) { + continue + } + ttf := TTFLight{} + ttf.UsedGIDs = map[uint16]bool{} + fn := filepath.Join(UserFontDir, f.Name()) + if err := load(fn, &ttf); err != nil { + return err + } + fn = strings.TrimSuffix(f.Name(), path.Ext(f.Name())) + //fmt.Printf("loading %s.ttf...\n", fn) + //fmt.Printf("Loaded %s:\n%s", fn, ttf) + UserFontMetrics[fn] = ttf + } + return nil +} + +// BoundingBox returns the font bounding box for a given font as specified in the corresponding AFM file. +func BoundingBox(fontName string) *types.Rectangle { + if IsCoreFont(fontName) { + return metrics.CoreFontMetrics[fontName].FBox + } + llx := UserFontMetrics[fontName].LLx + lly := UserFontMetrics[fontName].LLy + urx := UserFontMetrics[fontName].URx + ury := UserFontMetrics[fontName].URy + return types.NewRectangle(llx, lly, urx, ury) +} + +// CharWidth returns the character width for a char and font in glyph space units. +func CharWidth(fontName string, r rune) int { + if IsCoreFont(fontName) { + return metrics.CoreFontCharWidth(fontName, int(r)) + } + ttf, ok := UserFontMetrics[fontName] + if !ok { + fmt.Fprintf(os.Stderr, "pdfcpu: user font not loaded: %s\n", fontName) + os.Exit(1) + } + + pos, ok := ttf.Chars[uint32(r)] + if !ok { + pos = 0 + } + return int(ttf.GlyphWidths[pos]) +} + +// UserSpaceUnits transforms glyphSpaceUnits into userspace units. +func UserSpaceUnits(glyphSpaceUnits float64, fontScalingFactor int) float64 { + return glyphSpaceUnits / 1000 * float64(fontScalingFactor) +} + +// GlyphSpaceUnits transforms userSpaceUnits into glyphspace Units. +func GlyphSpaceUnits(userSpaceUnits float64, fontScalingFactor int) float64 { + return userSpaceUnits * 1000 / float64(fontScalingFactor) +} + +func fontScalingFactor(glyphSpaceUnits, userSpaceUnits float64) int { + return int(math.Round(userSpaceUnits / glyphSpaceUnits * 1000)) +} + +// Descent returns fontname's descent in userspace units corresponding to fontSize. +func Descent(fontName string, fontSize int) float64 { + fbb := BoundingBox(fontName) + return UserSpaceUnits(-fbb.LL.Y, fontSize) +} + +// Ascent returns fontname's ascent in userspace units corresponding to fontSize. +func Ascent(fontName string, fontSize int) float64 { + fbb := BoundingBox(fontName) + return UserSpaceUnits(fbb.Height()+fbb.LL.Y, fontSize) +} + +// LineHeight returns fontname's line height in userspace units corresponding to fontSize. +func LineHeight(fontName string, fontSize int) float64 { + fbb := BoundingBox(fontName) + return UserSpaceUnits(fbb.Height(), fontSize) +} + +func glyphSpaceWidth(text, fontName string) int { + var w int + if IsCoreFont(fontName) { + for i := 0; i < len(text); i++ { + c := text[i] + w += CharWidth(fontName, rune(c)) + } + return w + } + for _, r := range text { + w += CharWidth(fontName, r) + } + return w +} + +// TextWidth represents the width in user space units for a given text string, font name and font size. +func TextWidth(text, fontName string, fontSize int) float64 { + w := glyphSpaceWidth(text, fontName) + return UserSpaceUnits(float64(w), fontSize) +} + +// Size returns the needed font size (aka. font scaling factor) in points +// for rendering a given text string using a given font name with a given user space width. +func Size(text, fontName string, width float64) int { + w := glyphSpaceWidth(text, fontName) + return fontScalingFactor(float64(w), width) +} + +// UserSpaceFontBBox returns the font box for given font name and font size in user space coordinates. +func UserSpaceFontBBox(fontName string, fontSize int) *types.Rectangle { + fontBBox := BoundingBox(fontName) + llx := UserSpaceUnits(fontBBox.LL.X, fontSize) + lly := UserSpaceUnits(fontBBox.LL.Y, fontSize) + urx := UserSpaceUnits(fontBBox.UR.X, fontSize) + ury := UserSpaceUnits(fontBBox.UR.Y, fontSize) + return types.NewRectangle(llx, lly, urx, ury) +} + +// IsCoreFont returns true for the 14 PDF standard Type 1 fonts. +func IsCoreFont(fontName string) bool { + _, ok := metrics.CoreFontMetrics[fontName] + return ok +} + +// CoreFontNames returns a list of the 14 PDF standard Type 1 fonts. +func CoreFontNames() []string { + ss := []string{} + for fontName := range metrics.CoreFontMetrics { + ss = append(ss, fontName) + } + return ss +} + +// IsUserFont returns true for installed TrueType fonts. +func IsUserFont(fontName string) bool { + _, ok := UserFontMetrics[fontName] + return ok +} + +// UserFontNames return a list of all installed TrueType fonts. +func UserFontNames() []string { + ss := []string{} + for fontName := range UserFontMetrics { + ss = append(ss, fontName) + } + return ss +} + +// UserFontNamesVerbose return a list of all installed TrueType fonts including glyph count. +func UserFontNamesVerbose() []string { + ss := []string{} + for fName, ttf := range UserFontMetrics { + s := fName + " (" + strconv.Itoa(ttf.GlyphCount) + " glyphs)" + ss = append(ss, s) + } + return ss +} + +// SupportedFont returns true for core fonts or user installed fonts. +func SupportedFont(fontName string) bool { + return IsCoreFont(fontName) || IsUserFont(fontName) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/log/log.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/log/log.go new file mode 100644 index 0000000..b1eae2e --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/log/log.go @@ -0,0 +1,239 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package log provides a logging abstraction. +package log + +import ( + "log" + "os" +) + +// Logger defines an interface for logging messages. +type Logger interface { + + // Printf logs a formatted string. + Printf(format string, args ...interface{}) + + // Println logs a line. + Println(args ...interface{}) + + // Fatalf is equivalent to Printf() followed by a program abort. + Fatalf(format string, args ...interface{}) + + // Fatalln is equivalent to Println() followed by a progam abort. + Fatalln(args ...interface{}) +} + +type logger struct { + log Logger +} + +// pdfcpu's loggers. +var ( + + // Horizontal loggers + Debug = &logger{} + Info = &logger{} + Stats = &logger{} + Trace = &logger{} + + // Vertical loggers + Parse = &logger{} + Read = &logger{} + Validate = &logger{} + Optimize = &logger{} + Write = &logger{} + CLI = &logger{} +) + +// SetDebugLogger sets the debug logger. +func SetDebugLogger(log Logger) { + Debug.log = log +} + +// SetInfoLogger sets the info logger. +func SetInfoLogger(log Logger) { + Info.log = log +} + +// SetStatsLogger sets the stats logger. +func SetStatsLogger(log Logger) { + Stats.log = log +} + +// SetTraceLogger sets the trace logger. +func SetTraceLogger(log Logger) { + Trace.log = log +} + +// SetParseLogger sets the parse logger. +func SetParseLogger(log Logger) { + Parse.log = log +} + +// SetReadLogger sets the read logger. +func SetReadLogger(log Logger) { + Read.log = log +} + +// SetValidateLogger sets the validate logger. +func SetValidateLogger(log Logger) { + Validate.log = log +} + +// SetOptimizeLogger sets the optimize logger. +func SetOptimizeLogger(log Logger) { + Optimize.log = log +} + +// SetWriteLogger sets the write logger. +func SetWriteLogger(log Logger) { + Write.log = log +} + +// SetCLILogger sets the api logger. +func SetCLILogger(log Logger) { + CLI.log = log +} + +// SetDefaultDebugLogger sets the default debug logger. +func SetDefaultDebugLogger() { + SetDebugLogger(log.New(os.Stderr, "DEBUG: ", log.Ldate|log.Ltime)) +} + +// SetDefaultInfoLogger sets the default info logger. +func SetDefaultInfoLogger() { + SetInfoLogger(log.New(os.Stderr, " INFO: ", log.Ldate|log.Ltime)) +} + +// SetDefaultStatsLogger sets the default stats logger. +func SetDefaultStatsLogger() { + SetStatsLogger(log.New(os.Stderr, "STATS: ", log.Ldate|log.Ltime)) +} + +// SetDefaultTraceLogger sets the default trace logger. +func SetDefaultTraceLogger() { + SetTraceLogger(log.New(os.Stderr, "TRACE: ", log.Ldate|log.Ltime)) +} + +// SetDefaultParseLogger sets the default parse logger. +func SetDefaultParseLogger() { + SetParseLogger(log.New(os.Stderr, "PARSE: ", log.Ldate|log.Ltime)) +} + +// SetDefaultReadLogger sets the default read logger. +func SetDefaultReadLogger() { + SetReadLogger(log.New(os.Stderr, " READ: ", log.Ldate|log.Ltime)) +} + +// SetDefaultValidateLogger sets the default validate logger. +func SetDefaultValidateLogger() { + SetValidateLogger(log.New(os.Stderr, "VALID: ", log.Ldate|log.Ltime)) +} + +// SetDefaultOptimizeLogger sets the default optimize logger. +func SetDefaultOptimizeLogger() { + SetOptimizeLogger(log.New(os.Stderr, " OPT: ", log.Ldate|log.Ltime)) +} + +// SetDefaultWriteLogger sets the default write logger. +func SetDefaultWriteLogger() { + SetWriteLogger(log.New(os.Stderr, "WRITE: ", log.Ldate|log.Ltime)) +} + +// SetDefaultCLILogger sets the default cli logger. +func SetDefaultCLILogger() { + SetCLILogger(log.New(os.Stdout, "", 0)) +} + +// SetDefaultLoggers sets all loggers to their default logger. +func SetDefaultLoggers() { + SetDefaultDebugLogger() + SetDefaultInfoLogger() + SetDefaultStatsLogger() + SetDefaultTraceLogger() + SetDefaultParseLogger() + SetDefaultReadLogger() + SetDefaultValidateLogger() + SetDefaultOptimizeLogger() + SetDefaultWriteLogger() + SetDefaultCLILogger() +} + +// DisableLoggers turns off all logging. +func DisableLoggers() { + SetDebugLogger(nil) + SetInfoLogger(nil) + SetStatsLogger(nil) + SetTraceLogger(nil) + SetParseLogger(nil) + SetReadLogger(nil) + SetValidateLogger(nil) + SetOptimizeLogger(nil) + SetWriteLogger(nil) + SetCLILogger(nil) +} + +// IsTraceLoggerEnabled returns true if the Trace Logger is enabled. +func IsTraceLoggerEnabled() bool { + return Trace.log != nil +} + +// IsCLILoggerEnabled returns true if the CLI Logger is enabled. +func IsCLILoggerEnabled() bool { + return CLI.log != nil +} + +// Printf writes a formatted message to the log. +func (l *logger) Printf(format string, args ...interface{}) { + + if l.log == nil { + return + } + + l.log.Printf(format, args...) +} + +// Println writes a line to the log. +func (l *logger) Println(args ...interface{}) { + + if l.log == nil { + return + } + + l.log.Println(args...) +} + +// Fatalf is equivalent to Printf() followed by a program abort. +func (l *logger) Fatalf(format string, args ...interface{}) { + + if l.log == nil { + return + } + + l.log.Fatalf(format, args...) +} + +// Fatalf is equivalent to Println() followed by a program abort. +func (l *logger) Fatalln(args ...interface{}) { + + if l.log == nil { + return + } + + l.log.Fatalln(args...) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/array.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/array.go new file mode 100644 index 0000000..0fde547 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/array.go @@ -0,0 +1,225 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/log" +) + +// Array represents a PDF array object. +type Array []Object + +// NewStringArray returns a PDFArray with StringLiteral entries. +func NewStringArray(sVars ...string) Array { + + a := Array{} + + for _, s := range sVars { + a = append(a, StringLiteral(s)) + } + + return a +} + +// NewNameArray returns a PDFArray with Name entries. +func NewNameArray(sVars ...string) Array { + + a := Array{} + + for _, s := range sVars { + a = append(a, Name(s)) + } + + return a +} + +// NewNumberArray returns a PDFArray with Float entries. +func NewNumberArray(fVars ...float64) Array { + + a := Array{} + + for _, f := range fVars { + a = append(a, Float(f)) + } + + return a +} + +// NewIntegerArray returns a PDFArray with Integer entries. +func NewIntegerArray(fVars ...int) Array { + + a := Array{} + + for _, f := range fVars { + a = append(a, Integer(f)) + } + + return a +} + +// Clone returns a clone of a. +func (a Array) Clone() Object { + a1 := Array(make([]Object, len(a))) + for k, v := range a { + if v != nil { + v = v.Clone() + } + a1[k] = v + } + return a1 +} + +func (a Array) contains(o Object, xRefTable *XRefTable) (bool, error) { + for _, e := range a { + ok, err := equalObjects(e, o, xRefTable) + if err != nil { + return false, err + } + if ok { + return true, nil + } + } + return false, nil +} + +func (a Array) indentedString(level int) string { + + logstr := []string{"["} + tabstr := strings.Repeat("\t", level) + first := true + sepstr := "" + + for _, entry := range a { + + if first { + first = false + sepstr = "" + } else { + sepstr = " " + } + + if subdict, ok := entry.(Dict); ok { + dictstr := subdict.indentedString(level + 1) + logstr = append(logstr, fmt.Sprintf("\n%[1]s%[2]s\n%[1]s", tabstr, dictstr)) + first = true + continue + } + + if array, ok := entry.(Array); ok { + arrstr := array.indentedString(level + 1) + logstr = append(logstr, fmt.Sprintf("%s%s", sepstr, arrstr)) + continue + } + + logstr = append(logstr, fmt.Sprintf("%s%v", sepstr, entry)) + } + + logstr = append(logstr, "]") + + return strings.Join(logstr, "") +} + +func (a Array) String() string { + return a.indentedString(1) +} + +// PDFString returns a string representation as found in and written to a PDF file. +func (a Array) PDFString() string { + + logstr := []string{} + logstr = append(logstr, "[") + first := true + var sepstr string + + for _, entry := range a { + + if first { + first = false + sepstr = "" + } else { + sepstr = " " + } + + if entry == nil { + logstr = append(logstr, fmt.Sprintf("%snull", sepstr)) + continue + } + + d, ok := entry.(Dict) + if ok { + logstr = append(logstr, fmt.Sprintf("%s", d.PDFString())) + continue + } + + a, ok := entry.(Array) + if ok { + logstr = append(logstr, fmt.Sprintf("%s", a.PDFString())) + continue + } + + ir, ok := entry.(IndirectRef) + if ok { + logstr = append(logstr, fmt.Sprintf("%s%s", sepstr, ir.PDFString())) + continue + } + + n, ok := entry.(Name) + if ok { + logstr = append(logstr, fmt.Sprintf("%s", n.PDFString())) + continue + } + + i, ok := entry.(Integer) + if ok { + logstr = append(logstr, fmt.Sprintf("%s%s", sepstr, i.PDFString())) + continue + } + + f, ok := entry.(Float) + if ok { + logstr = append(logstr, fmt.Sprintf("%s%s", sepstr, f.PDFString())) + continue + } + + b, ok := entry.(Boolean) + if ok { + logstr = append(logstr, fmt.Sprintf("%s%s", sepstr, b.PDFString())) + continue + } + sl, ok := entry.(StringLiteral) + if ok { + logstr = append(logstr, fmt.Sprintf("%s%s", sepstr, sl.PDFString())) + continue + } + + hl, ok := entry.(HexLiteral) + if ok { + logstr = append(logstr, fmt.Sprintf("%s%s", sepstr, hl.PDFString())) + continue + } + + log.Info.Fatalf("PDFArray.PDFString(): entry of unknown object type: %[1]T %[1]v\n", entry) + } + + logstr = append(logstr, "]") + + return strings.Join(logstr, "") +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/attach.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/attach.go new file mode 100644 index 0000000..6a3f55e --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/attach.go @@ -0,0 +1,380 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bytes" + "fmt" + "io" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/filter" + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +func decodeFileSpecStreamDict(sd *StreamDict, id string) error { + fpl := sd.FilterPipeline + + if fpl == nil { + sd.Content = sd.Raw + return nil + } + + // Ignore filter chains with length > 1 + if len(fpl) > 1 { + log.Debug.Printf("decodedFileSpecStreamDict: ignore %s, more than 1 filter.\n", id) + return nil + } + + // Only FlateDecode supported. + if fpl[0].Name != filter.Flate { + log.Debug.Printf("decodedFileSpecStreamDict: ignore %s, %s filter unsupported.\n", id, fpl[0].Name) + return nil + } + + // Decode streamDict for supported filters only. + return sd.Decode() +} + +func fileSpectStreamFileName(xRefTable *XRefTable, d Dict) (string, error) { + o, found := d.Find("UF") + if found { + fileName, err := xRefTable.DereferenceStringOrHexLiteral(o, V10, nil) + return fileName, err + } + + o, found = d.Find("F") + if !found { + return "", errors.New("") + } + + fileName, err := xRefTable.DereferenceStringOrHexLiteral(o, V10, nil) + return fileName, err +} + +func fileSpecStreamDict(xRefTable *XRefTable, d Dict) (*StreamDict, error) { + // Entry EF is a dict holding a stream dict in entry F. + o, found := d.Find("EF") + if !found || o == nil { + return nil, nil + } + + d, err := xRefTable.DereferenceDict(o) + if err != nil || o == nil { + return nil, err + } + + // Entry F holds the embedded file's data. + o, found = d.Find("F") + if !found || o == nil { + return nil, nil + } + + sd, _, err := xRefTable.DereferenceStreamDict(o) + return sd, err +} + +func fileSpecStreamDictInfo(xRefTable *XRefTable, id string, o Object, decode bool) (*StreamDict, string, string, *time.Time, error) { + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return nil, "", "", nil, err + } + + var desc string + o, found := d.Find("Desc") + if found { + desc, err = xRefTable.DereferenceStringOrHexLiteral(o, V10, nil) + if err != nil { + return nil, "", "", nil, err + } + } + + fileName, err := fileSpectStreamFileName(xRefTable, d) + if err != nil { + return nil, "", "", nil, err + } + + sd, err := fileSpecStreamDict(xRefTable, d) + if err != nil { + return nil, "", "", nil, err + } + + var modDate *time.Time + if d = sd.DictEntry("Params"); d != nil { + if s := d.StringEntry("ModDate"); s != nil { + dt, ok := DateTime(*s) + if !ok { + return nil, desc, "", nil, errors.New("pdfcpu: invalid date ModDate") + } + modDate = &dt + } + } + + err = decodeFileSpecStreamDict(sd, id) + + return sd, desc, fileName, modDate, err +} + +// Attachment is a Reader representing a PDF attachment. +type Attachment struct { + io.Reader // attachment data + ID string // id + FileName string // filename + Desc string // description + ModTime *time.Time // time of last modification (optional) +} + +func (a Attachment) String() string { + return fmt.Sprintf("Attachment: id:%s desc:%s modTime:%s", a.ID, a.Desc, a.ModTime) +} + +// ListAttachments returns a slice of attachment stubs (attachment w/o data). +func (ctx *Context) ListAttachments() ([]Attachment, error) { + xRefTable := ctx.XRefTable + if !xRefTable.Valid { + if err := xRefTable.LocateNameTree("EmbeddedFiles", false); err != nil { + return nil, err + } + } + if xRefTable.Names["EmbeddedFiles"] == nil { + return nil, nil + } + + aa := []Attachment{} + + createAttachmentStub := func(xRefTable *XRefTable, id string, o Object) error { + decode := false + _, desc, fileName, modTime, err := fileSpecStreamDictInfo(xRefTable, id, o, decode) + if err != nil { + return err + } + aa = append(aa, Attachment{nil, id, fileName, desc, modTime}) + return nil + } + + // Extract stub info. + if err := ctx.Names["EmbeddedFiles"].Process(xRefTable, createAttachmentStub); err != nil { + return nil, err + } + + return aa, nil +} + +// AddAttachment adds a. +func (ctx *Context) AddAttachment(a Attachment, useCollection bool) error { + xRefTable := ctx.XRefTable + if err := xRefTable.LocateNameTree("EmbeddedFiles", true); err != nil { + return err + } + + if useCollection { + // Ensure a Collection entry in the catalog. + if err := xRefTable.EnsureCollection(); err != nil { + return err + } + } + + ir, err := xRefTable.NewFileSpectDictForAttachment(a) + if err != nil { + return err + } + + return xRefTable.Names["EmbeddedFiles"].Add(xRefTable, encodeUTF16String(a.ID), *ir) +} + +var errContentMatch = errors.New("name tree content match") + +// SearchEmbeddedFilesNameTreeNodeByContent tries to identify a name tree by content. +func (ctx *Context) SearchEmbeddedFilesNameTreeNodeByContent(s string) (*string, Object, error) { + + var ( + k *string + v Object + ) + + identifyAttachmentStub := func(xRefTable *XRefTable, id string, o Object) error { + decode := false + _, desc, fileName, _, err := fileSpecStreamDictInfo(xRefTable, id, o, decode) + if err != nil { + return err + } + if s == fileName || s == desc { + k = &id + v = o + return errContentMatch + } + return nil + } + + if err := ctx.Names["EmbeddedFiles"].Process(ctx.XRefTable, identifyAttachmentStub); err != nil { + if err != errContentMatch { + return nil, nil, err + } + // Node identified. + return k, v, nil + } + + return nil, nil, nil +} + +func (ctx *Context) removeAttachment(id string) (bool, error) { + log.CLI.Printf("removing %s\n", id) + xRefTable := ctx.XRefTable + // EmbeddedFiles name tree containing at least one key value pair. + empty, ok, err := xRefTable.Names["EmbeddedFiles"].Remove(xRefTable, id) + if err != nil { + return false, err + } + if empty { + // Delete name tree root object. + if err := xRefTable.RemoveEmbeddedFilesNameTree(); err != nil { + return false, err + } + } + if !ok { + // Try to identify name tree node by content. + k, _, err := ctx.SearchEmbeddedFilesNameTreeNodeByContent(id) + if err != nil { + return false, err + } + if k == nil { + log.CLI.Printf("attachment %s not found", id) + return false, nil + } + empty, _, err = xRefTable.Names["EmbeddedFiles"].Remove(xRefTable, *k) + if err != nil { + return false, err + } + if empty { + // Delete name tree root object. + if err := xRefTable.RemoveEmbeddedFilesNameTree(); err != nil { + return false, err + } + } + } + return true, nil +} + +// RemoveAttachments removes attachments with given id and returns true if anything removed. +func (ctx *Context) RemoveAttachments(ids []string) (bool, error) { + // Note: Any remove operation may be deleting the only key value pair of this name tree. + xRefTable := ctx.XRefTable + if !xRefTable.Valid { + if err := xRefTable.LocateNameTree("EmbeddedFiles", false); err != nil { + return false, err + } + } + if xRefTable.Names["EmbeddedFiles"] == nil { + return false, errors.Errorf("no attachments available.") + } + + if ids == nil || len(ids) == 0 { + // Remove all attachments - delete name tree root object. + log.CLI.Println("removing all attachments") + if err := xRefTable.RemoveEmbeddedFilesNameTree(); err != nil { + return false, err + } + return true, nil + } + + for _, id := range ids { + found, err := ctx.removeAttachment(id) + if err != nil { + return false, err + } + if !found { + return false, nil + } + } + + return true, nil +} + +// RemoveAttachment removes a and returns true on success. +func (ctx *Context) RemoveAttachment(a Attachment) (bool, error) { + return ctx.RemoveAttachments([]string{a.ID}) +} + +// ExtractAttachments extracts attachments with id. +func (ctx *Context) ExtractAttachments(ids []string) ([]Attachment, error) { + xRefTable := ctx.XRefTable + if !xRefTable.Valid { + if err := xRefTable.LocateNameTree("EmbeddedFiles", false); err != nil { + return nil, err + } + } + if xRefTable.Names["EmbeddedFiles"] == nil { + return nil, errors.Errorf("no attachments available.") + } + + aa := []Attachment{} + + createAttachment := func(xRefTable *XRefTable, id string, o Object) error { + decode := true + sd, desc, fileName, modTime, err := fileSpecStreamDictInfo(xRefTable, id, o, decode) + if err != nil { + return err + } + a := Attachment{Reader: bytes.NewReader(sd.Content), ID: id, FileName: fileName, Desc: desc, ModTime: modTime} + aa = append(aa, a) + return nil + } + + // Search with UF,F,Desc + if ids != nil && len(ids) > 0 { + for _, id := range ids { + v, ok := ctx.Names["EmbeddedFiles"].Value(id) + if !ok { + // Try to identify name tree node by content. + k, o, err := ctx.SearchEmbeddedFilesNameTreeNodeByContent(id) + if err != nil { + return nil, err + } + if k == nil { + log.CLI.Printf("attachment %s not found", id) + log.Info.Printf("pdfcpu: extractAttachments: %s not found", id) + continue + } + v = o + } + if err := createAttachment(ctx.XRefTable, id, v); err != nil { + return nil, err + } + } + return aa, nil + } + + // Extract all files. + if err := ctx.Names["EmbeddedFiles"].Process(ctx.XRefTable, createAttachment); err != nil { + return nil, err + } + + return aa, nil +} + +// ExtractAttachment extracts a fully populated attachment. +func (ctx *Context) ExtractAttachment(a Attachment) (*Attachment, error) { + aa, err := ctx.ExtractAttachments([]string{a.ID}) + if err != nil || len(aa) == 0 { + return nil, err + } + if len(aa) > 1 { + return nil, errors.Errorf("pdfcpu: unexpected number of attachments: %d", len(aa)) + } + return &aa[0], nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/bookmarks.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/bookmarks.go new file mode 100644 index 0000000..cef65fe --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/bookmarks.go @@ -0,0 +1,145 @@ +/* +Copyright 2020 The pdf Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import "github.com/pkg/errors" + +var ( + errNoBookmarks = errors.New("pdfcpu: no bookmarks available") + errCorruptedDests = errors.New("pdfcpu: corrupted named destination") +) + +// Bookmark represents an outline item at some level including page span info. +type Bookmark struct { + Title string + PageFrom int + PageThru int // >= pageFrom and reaches until before pageFrom of the next bookmark. +} + +func (ctx *Context) dereferenceDestinationArray(key string) (Array, error) { + o, ok := ctx.Names["Dests"].Value(key) + if !ok { + return nil, errCorruptedDests + } + return ctx.DereferenceArray(o) +} + +func (ctx *Context) positionToOutlineTreeLevel1() (Dict, *IndirectRef, error) { + // Load Dests nametree. + if err := ctx.LocateNameTree("Dests", false); err != nil { + return nil, nil, err + } + + ir, err := ctx.Outlines() + if err != nil { + return nil, nil, err + } + if ir == nil { + return nil, nil, errNoBookmarks + } + + d, err := ctx.DereferenceDict(*ir) + if err != nil { + return nil, nil, err + } + if d == nil { + return nil, nil, errNoBookmarks + } + + first := d.IndirectRefEntry("First") + last := d.IndirectRefEntry("Last") + + // We consider Bookmarks at level 1 or 2 only. + for *first == *last { + if d, err = ctx.DereferenceDict(*first); err != nil { + return nil, nil, err + } + first = d.IndirectRefEntry("First") + last = d.IndirectRefEntry("Last") + } + + return d, first, nil +} + +// BookmarksForOutlineLevel1 returns bookmarks incliuding page span info. +func (ctx *Context) BookmarksForOutlineLevel1() ([]Bookmark, error) { + d, first, err := ctx.positionToOutlineTreeLevel1() + if err != nil { + return nil, err + } + + bms := []Bookmark{} + + // Process outline items. + for ir := first; ir != nil; ir = d.IndirectRefEntry("Next") { + + if d, err = ctx.DereferenceDict(*ir); err != nil { + return nil, err + } + + title, _ := Text(d["Title"]) + + dest, found := d["Dest"] + if !found { + return nil, errNoBookmarks + } + + var ir IndirectRef + + dest, _ = ctx.Dereference(dest) + + switch dest := dest.(type) { + case Name: + arr, err := ctx.dereferenceDestinationArray(dest.Value()) + if err != nil { + return nil, err + } + ir = arr[0].(IndirectRef) + case StringLiteral: + arr, err := ctx.dereferenceDestinationArray(dest.Value()) + if err != nil { + return nil, err + } + ir = arr[0].(IndirectRef) + case HexLiteral: + arr, err := ctx.dereferenceDestinationArray(dest.Value()) + if err != nil { + return nil, err + } + ir = arr[0].(IndirectRef) + case Array: + ir = dest[0].(IndirectRef) + + } + + pageFrom, err := ctx.PageNumber(ir.ObjectNumber.Value()) + if err != nil { + return nil, err + } + + if len(bms) > 0 { + if pageFrom > bms[len(bms)-1].PageFrom { + bms[len(bms)-1].PageThru = pageFrom - 1 + } else { + bms[len(bms)-1].PageThru = bms[len(bms)-1].PageFrom + } + } + bms = append(bms, Bookmark{Title: title, PageFrom: pageFrom}) + } + + return bms, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/boxes.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/boxes.go new file mode 100644 index 0000000..e6a3a74 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/boxes.go @@ -0,0 +1,1211 @@ +/* +Copyright 2020 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + "strconv" + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/types" + "github.com/pkg/errors" +) + +// Box is a rectangular region in user space +// expressed either explicitly via Rect +// or implicitly via margins applied to the containing parent box. +// Media box serves as parent box for crop box. +// Crop box serves as parent box for trim, bleed and art box. +type Box struct { + Rect *Rectangle // Rectangle in user space. + Inherited bool // Media box and Crop box may be inherited. + RefBox string // Use position of another box, + // Margins to parent box in points. + // Relative to parent box if 0 < x < 0.5 + MLeft, MRight float64 + MTop, MBot float64 + // Relative position within parent box + Dim *Dim // dimensions + Pos anchor // position anchor within parent box, one of tl,tc,tr,l,c,r,bl,bc,br. + Dx, Dy int // anchor offset +} + +// PageBoundaries represent the defined PDF page boundaries. +type PageBoundaries struct { + Media, Crop, Trim, Bleed, Art *Box +} + +// SelectAll selects all page boundaries. +func (pb *PageBoundaries) SelectAll() { + b := &Box{} + pb.Media, pb.Crop, pb.Trim, pb.Bleed, pb.Art = b, b, b, b, b +} + +func (pb PageBoundaries) String() string { + ss := []string{} + if pb.Media != nil { + ss = append(ss, "mediaBox") + } + if pb.Crop != nil { + ss = append(ss, "cropBox") + } + if pb.Trim != nil { + ss = append(ss, "trimBox") + } + if pb.Bleed != nil { + ss = append(ss, "bleedBox") + } + if pb.Art != nil { + ss = append(ss, "artBox") + } + return strings.Join(ss, ", ") +} + +// MediaBox returns the effective mediabox for pb. +func (pb PageBoundaries) MediaBox() *Rectangle { + if pb.Media == nil { + return nil + } + return pb.Media.Rect +} + +// CropBox returns the effective cropbox for pb. +func (pb PageBoundaries) CropBox() *Rectangle { + if pb.Crop == nil || pb.Crop.Rect == nil { + return pb.MediaBox() + } + return pb.Crop.Rect +} + +// TrimBox returns the effective trimbox for pb. +func (pb PageBoundaries) TrimBox() *Rectangle { + if pb.Trim == nil || pb.Trim.Rect == nil { + return pb.CropBox() + } + return pb.Trim.Rect +} + +// BleedBox returns the effective bleedbox for pb. +func (pb PageBoundaries) BleedBox() *Rectangle { + if pb.Bleed == nil || pb.Bleed.Rect == nil { + return pb.CropBox() + } + return pb.Bleed.Rect +} + +// ArtBox returns the effective artbox for pb. +func (pb PageBoundaries) ArtBox() *Rectangle { + if pb.Art == nil || pb.Art.Rect == nil { + return pb.CropBox() + } + return pb.Art.Rect +} + +// ResolveBox resolves s and tries to assign an empty page boundary. +func (pb *PageBoundaries) ResolveBox(s string) error { + for _, k := range []string{"media", "crop", "trim", "bleed", "art"} { + b := &Box{} + if strings.HasPrefix(k, s) { + switch k { + case "media": + pb.Media = b + case "crop": + pb.Crop = b + case "trim": + pb.Trim = b + case "bleed": + pb.Bleed = b + case "art": + pb.Art = b + } + return nil + } + } + return errors.Errorf("pdfcpu: invalid box prefix: %s", s) +} + +// ParseBoxList parses a list of box types. +func ParseBoxList(s string) (*PageBoundaries, error) { + // A comma separated, unsorted list of values: + // + // m(edia), c(rop), t(rim), b(leed), a(rt) + + s = strings.TrimSpace(s) + if len(s) == 0 { + return nil, nil + } + pb := &PageBoundaries{} + for _, s := range strings.Split(s, ",") { + if err := pb.ResolveBox(strings.TrimSpace(s)); err != nil { + return nil, err + } + } + return pb, nil +} + +func resolveBoxType(s string) (string, error) { + for _, k := range []string{"media", "crop", "trim", "bleed", "art"} { + if strings.HasPrefix(k, s) { + return k, nil + } + } + return "", errors.Errorf("pdfcpu: invalid box type: %s", s) +} + +func processBox(b **Box, boxID, paramValueStr string, unit DisplayUnit) error { + var err error + if *b != nil { + return errors.Errorf("pdfcpu: duplicate box definition: %s", boxID) + } + // process box assignment + boxVal, err := resolveBoxType(paramValueStr) + if err == nil { + if boxVal == boxID { + return errors.Errorf("pdfcpu: invalid box self assigment: %s", boxID) + } + *b = &Box{RefBox: boxVal} + return nil + } + // process box definition + *b, err = ParseBox(paramValueStr, unit) + return err +} + +// ParsePageBoundaries parses a list of box definitions and assignments. +func ParsePageBoundaries(s string, unit DisplayUnit) (*PageBoundaries, error) { + // A sequence of box definitions/assignments: + // + // m(edia): {box} + // c(rop): {box} + // a(rt): {box} | b(leed) | c(rop) | m(edia) | t(rim) + // b(leed): {box} | a(rt) | c(rop) | m(edia) | t(rim) + // t(rim): {box} | a(rt) | b(leed) | c(rop) | m(edia) + + s = strings.TrimSpace(s) + if len(s) == 0 { + return nil, errors.New("pdfcpu: missing page boundaries in the form of box definitions/assignments") + } + pb := &PageBoundaries{} + for _, s := range strings.Split(s, ",") { + + s1 := strings.Split(s, ":") + if len(s1) != 2 { + return nil, errors.New("pdfcpu: invalid box assignment") + } + + paramPrefix := strings.TrimSpace(s1[0]) + paramValueStr := strings.TrimSpace(s1[1]) + + boxKey, err := resolveBoxType(paramPrefix) + if err != nil { + return nil, errors.New("pdfcpu: invalid box type") + } + + // process box definition + switch boxKey { + case "media": + if pb.Media != nil { + return nil, errors.New("pdfcpu: duplicate box definition: media") + } + // process media box definition + pb.Media, err = ParseBox(paramValueStr, unit) + + case "crop": + if pb.Crop != nil { + return nil, errors.New("pdfcpu: duplicate box definition: crop") + } + // process crop box definition + pb.Crop, err = ParseBox(paramValueStr, unit) + + case "trim": + err = processBox(&pb.Trim, "trim", paramValueStr, unit) + + case "bleed": + err = processBox(&pb.Bleed, "bleed", paramValueStr, unit) + + case "art": + err = processBox(&pb.Art, "art", paramValueStr, unit) + + } + + if err != nil { + return nil, err + } + } + return pb, nil +} + +func parseBoxByRectangle(s string, u DisplayUnit) (*Box, error) { + ss := strings.Fields(s) + if len(ss) != 4 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + f, err := strconv.ParseFloat(ss[0], 64) + if err != nil { + return nil, err + } + xmin := toUserSpace(f, u) + + f, err = strconv.ParseFloat(ss[1], 64) + if err != nil { + return nil, err + } + ymin := toUserSpace(f, u) + + f, err = strconv.ParseFloat(ss[2], 64) + if err != nil { + return nil, err + } + xmax := toUserSpace(f, u) + + f, err = strconv.ParseFloat(ss[3], 64) + if err != nil { + return nil, err + } + ymax := toUserSpace(f, u) + + if xmax < xmin { + xmin, xmax = xmax, xmin + } + + if ymax < ymin { + ymin, ymax = ymax, ymin + } + + return &Box{Rect: Rect(xmin, ymin, xmax, ymax)}, nil +} + +func parseBoxPercentage(s string) (float64, error) { + pct, err := strconv.ParseFloat(s, 64) + if err != nil { + return 0, err + } + if pct <= -50 || pct >= 50 { + return 0, errors.Errorf("pdfcpu: invalid margin percentage: %s must be < 50%%", s) + } + return pct / 100, nil +} + +func parseBoxBySingleMarginVal(s, s1 string, abs bool, u DisplayUnit) (*Box, error) { + if s1[len(s1)-1] == '%' { + // margin percentage + // 10.5% + // % has higher precedence than abs/rel. + s1 = s1[:len(s1)-1] + if len(s1) == 0 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + m, err := parseBoxPercentage(s1) + if err != nil { + return nil, err + } + return &Box{MLeft: m, MRight: m, MTop: m, MBot: m}, nil + } + m, err := strconv.ParseFloat(s1, 64) + if err != nil { + return nil, err + } + if !abs { + // 0.25 rel (=25%) + if m <= 0 || m >= .5 { + return nil, errors.Errorf("pdfcpu: invalid relative box margin: %f must be positive < 0.5", m) + } + return &Box{MLeft: m, MRight: m, MTop: m, MBot: m}, nil + } + // 10 + // 10 abs + // .5 + // .5 abs + m = toUserSpace(m, u) + return &Box{MLeft: m, MRight: m, MTop: m, MBot: m}, nil +} + +func parseBoxBy2Percentages(s, s1, s2 string) (*Box, error) { + // 10% 40% + // Parse vert margin. + s1 = s1[:len(s1)-1] + if len(s1) == 0 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + vm, err := parseBoxPercentage(s1) + if err != nil { + return nil, err + } + + if s2[len(s2)-1] != '%' { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + // Parse hor margin. + s2 = s2[:len(s2)-1] + if len(s2) == 0 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + hm, err := parseBoxPercentage(s2) + if err != nil { + return nil, err + } + return &Box{MLeft: hm, MRight: hm, MTop: vm, MBot: vm}, nil +} + +func parseBoxBy2MarginVals(s, s1, s2 string, abs bool, u DisplayUnit) (*Box, error) { + if s1[len(s1)-1] == '%' { + return parseBoxBy2Percentages(s, s1, s2) + } + + // 10 5 + // 10 5 abs + // .1 .5 + // .1 .5 abs + // .1 .4 rel + vm, err := strconv.ParseFloat(s1, 64) + if err != nil { + return nil, err + } + if !abs { + // eg 0.25 rel (=25%) + if vm <= 0 || vm >= .5 { + return nil, errors.Errorf("pdfcpu: invalid relative vertical box margin: %f must be positive < 0.5", vm) + } + } + hm, err := strconv.ParseFloat(s2, 64) + if err != nil { + return nil, err + } + if !abs { + // eg 0.25 rel (=25%) + if hm <= 0 || hm >= .5 { + return nil, errors.Errorf("pdfcpu: invalid relative horizontal box margin: %f must be positive < 0.5", hm) + } + } + if abs { + vm = toUserSpace(vm, u) + hm = toUserSpace(hm, u) + } + return &Box{MLeft: hm, MRight: hm, MTop: vm, MBot: vm}, nil +} + +func parseBoxBy3Percentages(s, s1, s2, s3 string) (*Box, error) { + // 10% 15.5% 10% + // Parse top margin. + s1 = s1[:len(s1)-1] + if len(s1) == 0 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + pct, err := strconv.ParseFloat(s1, 64) + if err != nil { + return nil, err + } + tm := pct / 100 + + if s2[len(s2)-1] != '%' { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + // Parse hor margin. + s2 = s2[:len(s2)-1] + if len(s2) == 0 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + hm, err := parseBoxPercentage(s2) + if err != nil { + return nil, err + } + + if s3[len(s3)-1] != '%' { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + // Parse bottom margin. + s3 = s3[:len(s3)-1] + if len(s3) == 0 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + pct, err = strconv.ParseFloat(s3, 64) + if err != nil { + return nil, err + } + bm := pct / 100 + if tm+bm >= 1 { + return nil, errors.Errorf("pdfcpu: vertical margin overflow: %s", s) + } + + return &Box{MLeft: hm, MRight: hm, MTop: tm, MBot: bm}, nil +} + +func parseBoxBy3MarginVals(s, s1, s2, s3 string, abs bool, u DisplayUnit) (*Box, error) { + if s1[len(s1)-1] == '%' { + return parseBoxBy3Percentages(s, s1, s2, s3) + } + + // 10 5 15 ... absolute, top:10 left,right:5 bottom:15 + // 10 5 15 abs ... absolute, top:10 left,right:5 bottom:15 + // .1 .155 .1 ... absolute, top:.1 left,right:.155 bottom:.1 + // .1 .155 .1 abs ... absolute, top:.1 left,right:.155 bottom:.1 + // .1 .155 .1 rel ... relative, top:.1 left,right:.155 bottom:.1 + tm, err := strconv.ParseFloat(s1, 64) + if err != nil { + return nil, err + } + + hm, err := strconv.ParseFloat(s2, 64) + if err != nil { + return nil, err + } + if !abs { + // eg 0.25 rel (=25%) + if hm <= 0 || hm >= .5 { + return nil, errors.Errorf("pdfcpu: invalid relative horizontal box margin: %f must be positive < 0.5", hm) + } + } + + bm, err := strconv.ParseFloat(s3, 64) + if err != nil { + return nil, err + } + if !abs && (tm+bm >= 1) { + return nil, errors.Errorf("pdfcpu: vertical margin overflow: %s", s) + } + + if abs { + tm = toUserSpace(tm, u) + hm = toUserSpace(hm, u) + bm = toUserSpace(bm, u) + } + return &Box{MLeft: hm, MRight: hm, MTop: tm, MBot: bm}, nil +} + +func parseBoxBy4Percentages(s, s1, s2, s3, s4 string) (*Box, error) { + // 10% 15.5% 10% + // Parse top margin. + s1 = s1[:len(s1)-1] + if len(s1) == 0 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + pct, err := strconv.ParseFloat(s1, 64) + if err != nil { + return nil, err + } + tm := pct / 100 + + if s2[len(s2)-1] != '%' { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + // Parse hor margin. + s2 = s2[:len(s2)-1] + if len(s2) == 0 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + hm, err := parseBoxPercentage(s2) + if err != nil { + return nil, err + } + + if s3[len(s3)-1] != '%' { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + // Parse bottom margin. + s3 = s3[:len(s3)-1] + if len(s3) == 0 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + pct, err = strconv.ParseFloat(s3, 64) + if err != nil { + return nil, err + } + bm := pct / 100 + if tm+bm >= 1 { + return nil, errors.Errorf("pdfcpu: vertical margin overflow: %s", s) + } + + return &Box{MLeft: hm, MRight: hm, MTop: tm, MBot: bm}, nil +} + +func parseBoxBy4MarginVals(s, s1, s2, s3, s4 string, abs bool, u DisplayUnit) (*Box, error) { + if s1[len(s1)-1] == '%' { + return parseBoxBy4Percentages(s, s1, s2, s3, s4) + } + + // 0.4 0.4 20 20 ... absolute, top:.4 right:.4 bottom:20 left:20 + // 0.4 0.4 .1 .1 ... absolute, top:.4 right:.4 bottom:.1 left:.1 + // 0.4 0.4 .1 .1 abs ... absolute, top:.4 right:.4 bottom:.1 left:.1 + // 0.4 0.4 .1 .1 rel ... relative, top:.4 right:.4 bottom:.1 left:.1 + + // Parse top margin. + tm, err := strconv.ParseFloat(s1, 64) + if err != nil { + return nil, err + } + + // Parse right margin. + rm, err := strconv.ParseFloat(s2, 64) + if err != nil { + return nil, err + } + + // Parse botton margin. + bm, err := strconv.ParseFloat(s3, 64) + if err != nil { + return nil, err + } + + // Parse left margin. + lm, err := strconv.ParseFloat(s1, 64) + if err != nil { + return nil, err + } + if !abs { + if tm+bm >= 1 { + return nil, errors.Errorf("pdfcpu: vertical margin overflow: %s", s) + } + if lm+rm >= 1 { + return nil, errors.Errorf("pdfcpu: horizontal margin overflow: %s", s) + } + } + + if abs { + tm = toUserSpace(tm, u) + rm = toUserSpace(rm, u) + bm = toUserSpace(bm, u) + lm = toUserSpace(lm, u) + } + return &Box{MLeft: lm, MRight: rm, MTop: tm, MBot: bm}, nil +} + +func parseBoxOffset(s string, b *Box, u DisplayUnit) error { + d := strings.Split(s, " ") + if len(d) != 2 { + return errors.Errorf("pdfcpu: illegal position offset string: need 2 numeric values, %s\n", s) + } + + f, err := strconv.ParseFloat(d[0], 64) + if err != nil { + return err + } + b.Dx = int(toUserSpace(f, u)) + + f, err = strconv.ParseFloat(d[1], 64) + if err != nil { + return err + } + b.Dy = int(toUserSpace(f, u)) + + return nil +} + +func parseBoxDimByPercentage(s, s1, s2 string, b *Box) error { + // 10% 40% + // Parse width. + s1 = s1[:len(s1)-1] + if len(s1) == 0 { + return errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + pct, err := strconv.ParseFloat(s1, 64) + if err != nil { + return err + } + if pct <= 0 || pct >= 100 { + return errors.Errorf("pdfcpu: invalid percentage: %s", s) + } + w := pct / 100 + + if s2[len(s2)-1] != '%' { + return errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + // Parse height. + s2 = s2[:len(s2)-1] + if len(s2) == 0 { + return errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + pct, err = strconv.ParseFloat(s2, 64) + if err != nil { + return err + } + if pct <= 0 || pct >= 100 { + return errors.Errorf("pdfcpu: invalid percentage: %s", s) + } + h := pct / 100 + b.Dim = &Dim{w, h} + return nil +} + +func parseBoxDimWidthAndHeight(s1, s2 string, abs bool) (float64, float64, error) { + var ( + w, h float64 + err error + ) + + w, err = strconv.ParseFloat(s1, 64) + if err != nil { + return w, h, err + } + if !abs { + // eg 0.25 rel (=25%) + if w <= 0 || w >= 1 { + return w, h, errors.Errorf("pdfcpu: invalid relative box width: %f must be positive < 1", w) + } + } + + h, err = strconv.ParseFloat(s2, 64) + if err != nil { + return w, h, err + } + if !abs { + // eg 0.25 rel (=25%) + if h <= 0 || h >= 1 { + return w, h, errors.Errorf("pdfcpu: invalid relative box height: %f must be positive < 1", h) + } + } + + return w, h, nil +} + +func parseBoxDim(s string, b *Box, u DisplayUnit) error { + ss := strings.Fields(s) + if len(ss) != 2 && len(ss) != 3 { + return errors.Errorf("pdfcpu: illegal dimension string: need 2 positive numeric values, %s\n", s) + } + abs := true + if len(ss) == 3 { + s1 := ss[2] + if s1 != "rel" && s1 != "abs" { + return errors.New("pdfcpu: illegal dimension string") + } + abs = s1 == "abs" + } + + s1, s2 := ss[0], ss[1] + if s1[len(s1)-1] == '%' { + return parseBoxDimByPercentage(s, s1, s2, b) + } + + w, h, err := parseBoxDimWidthAndHeight(s1, s2, abs) + if err != nil { + return err + } + + if abs { + w = toUserSpace(w, u) + h = toUserSpace(h, u) + } + b.Dim = &Dim{w, h} + return nil +} + +func parseBoxByPosWithinParent(s string, ss []string, u DisplayUnit) (*Box, error) { + b := &Box{Pos: Center} + for _, s := range ss { + + ss1 := strings.Split(s, ":") + if len(ss1) != 2 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + + paramPrefix := strings.TrimSpace(ss1[0]) + paramValueStr := strings.TrimSpace(ss1[1]) + + switch paramPrefix { + case "dim": + if err := parseBoxDim(paramValueStr, b, u); err != nil { + return nil, err + } + + case "pos": + a, err := parsePositionAnchor(paramValueStr) + if err != nil { + return nil, err + } + b.Pos = a + + case "off": + if err := parseBoxOffset(paramValueStr, b, u); err != nil { + return nil, err + } + + default: + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + } + if b.Dim == nil { + return nil, errors.New("pdfcpu: missing box definition attr dim") + } + return b, nil +} + +func parseBoxByMarginVals(ss []string, s string, abs bool, u DisplayUnit) (*Box, error) { + switch len(ss) { + case 1: + return parseBoxBySingleMarginVal(s, ss[0], abs, u) + case 2: + return parseBoxBy2MarginVals(s, ss[0], ss[1], abs, u) + case 3: + return parseBoxBy3MarginVals(s, ss[0], ss[1], ss[2], abs, u) + case 4: + return parseBoxBy4MarginVals(s, ss[0], ss[1], ss[2], ss[3], abs, u) + case 5: + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + return nil, nil +} + +// ParseBox parses a box definition. +func ParseBox(s string, u DisplayUnit) (*Box, error) { + // A rectangular region in userspace expressed in terms of + // a rectangle or margins relative to its parent box. + // Media box serves as parent/default for crop box. + // Crop box serves as parent/default for trim, bleed and art box: + + // [0 10 200 150] ... rectangle + + // 0.5 0.5 20 20 ... absolute, top:.5 right:.5 bottom:20 left:20 + // 0.5 0.5 .1 .1 abs ... absolute, top:.5 right:.5 bottom:.1 left:.1 + // 0.5 0.5 .1 .1 rel ... relative, top:.5 right:.5 bottom:20 left:20 + // 10 ... absolute, top,right,bottom,left:10 + // 10 5 ... absolute, top,bottom:10 left,right:5 + // 10 5 15 ... absolute, top:10 left,right:5 bottom:15 + // 5% <50% ... relative, top,right,bottom,left:5% of parent box width/height + // .1 .5 ... absolute, top,bottom:.1 left,right:.5 + // .1 .3 rel ... relative, top,bottom:.1=10% left,right:.3=30% + // -10 ... absolute, top,right,bottom,left enlarging the parent box as well + + // dim:30 30 ... 30 x 30 display units, anchored at center of parent box + // dim:30 30 abs ... 30 x 30 display units, anchored at center of parent box + // dim:.3 .3 rel ... 0.3 x 0.3 relative width/height of parent box, anchored at center of parent box + // dim:30% 30% ... 0.3 x 0.3 relative width/height of parent box, anchored at center of parent box + // pos:tl, dim:30 30 ... 0.3 x 0.3 relative width/height of parent box, anchored at top left corner of parent box + // pos:bl, off: 5 5, dim:30 30 ...30 x 30 display units with offset 5/5, anchored at bottom left corner of parent box + // pos:bl, off: -5 -5, dim:.3 .3 rel ...0.3 x 0.3 relative width/height and anchored at bottom left corner of parent box + + s = strings.TrimSpace(s) + if len(s) == 0 { + return nil, nil + } + + if s[0] == '[' && s[len(s)-1] == ']' { + // Rectangle in PDF Array notation. + return parseBoxByRectangle(s[1:len(s)-1], u) + } + + // Via relative position within parent box. + ss := strings.Split(s, ",") + if len(ss) > 3 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + if len(ss) > 1 || strings.HasPrefix(ss[0], "dim") { + return parseBoxByPosWithinParent(s, ss, u) + } + + // Via margins relative to parent box. + ss = strings.Fields(s) + if len(ss) > 5 { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + if len(ss) == 1 && (ss[0] == "abs" || ss[0] == "rel") { + return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s) + } + + abs := true + l := len(ss) - 1 + s1 := ss[l] + if s1 == "rel" || s1 == "abs" { + abs = s1 == "abs" + ss = ss[:l] + } + + return parseBoxByMarginVals(ss, s, abs, u) +} + +// ListPageBoundaries lists page boundaries specified in wantPB for selected pages. +func (ctx *Context) ListPageBoundaries(selectedPages IntSet, wantPB *PageBoundaries) ([]string, error) { + unit := ctx.unit() + // TODO ctx.PageBoundaries(selectedPages) + pbs, err := ctx.PageBoundaries() + if err != nil { + return nil, err + } + ss := []string{} + for i, pb := range pbs { + if _, found := selectedPages[i+1]; !found { + continue + } + ss = append(ss, fmt.Sprintf("Page %d:", i+1)) + if wantPB.Media != nil { + s := "" + if pb.Media.Inherited { + s = "(inherited)" + } + ss = append(ss, fmt.Sprintf(" MediaBox (%s) %v %s", unit, pb.MediaBox().Format(ctx.Unit), s)) + } + if wantPB.Crop != nil { + s := "" + if pb.Crop == nil { + s = "(default)" + } else if pb.Crop.Inherited { + s = "(inherited)" + } + ss = append(ss, fmt.Sprintf(" CropBox (%s) %v %s", unit, pb.CropBox().Format(ctx.Unit), s)) + } + if wantPB.Trim != nil { + s := "" + if pb.Trim == nil { + s = "(default)" + } + ss = append(ss, fmt.Sprintf(" TrimBox (%s) %v %s", unit, pb.TrimBox().Format(ctx.Unit), s)) + } + if wantPB.Bleed != nil { + s := "" + if pb.Bleed == nil { + s = "(default)" + } + ss = append(ss, fmt.Sprintf(" BleedBox (%s) %v %s", unit, pb.BleedBox().Format(ctx.Unit), s)) + } + if wantPB.Art != nil { + s := "" + if pb.Art == nil { + s = "(default)" + } + ss = append(ss, fmt.Sprintf(" ArtBox (%s) %v %s", unit, pb.ArtBox().Format(ctx.Unit), s)) + } + ss = append(ss, "") + } + + return ss, nil +} + +// RemovePageBoundaries removes page boundaries specified by pb for selected pages. +// The media box is mandatory (inherited or not) and can't be removed. +// A removed crop box defaults to the media box. +// Removed trim/bleed/art boxes default to the crop box. +func (ctx *Context) RemovePageBoundaries(selectedPages IntSet, pb *PageBoundaries) error { + for k, v := range selectedPages { + if !v { + continue + } + d, inhPAttrs, err := ctx.PageDict(k, false) + if err != nil { + return err + } + if pb.Crop != nil { + if oldVal := d.Delete("CropBox"); oldVal == nil { + d.Insert("CropBox", inhPAttrs.mediaBox.Array()) + } + } + if pb.Trim != nil { + d.Delete("TrimBox") + } + if pb.Bleed != nil { + d.Delete("BleedBox") + } + if pb.Art != nil { + d.Delete("ArtBox") + } + } + return nil +} + +func boxLowerLeftCorner(r *Rectangle, w, h float64, a anchor) types.Point { + var p types.Point + + switch a { + + case TopLeft: + p.X = r.LL.X + p.Y = r.UR.Y - h + + case TopCenter: + p.X = r.UR.X - r.Width()/2 - w/2 + p.Y = r.UR.Y - h + + case TopRight: + p.X = r.UR.X - w + p.Y = r.UR.Y - h + + case Left: + p.X = r.LL.X + p.Y = r.UR.Y - r.Height()/2 - h/2 + + case Center: + p.X = r.UR.X - r.Width()/2 - w/2 + p.Y = r.UR.Y - r.Height()/2 - h/2 + + case Right: + p.X = r.UR.X - w + p.Y = r.UR.Y - r.Height()/2 - h/2 + + case BottomLeft: + p.X = r.LL.X + p.Y = r.LL.Y + + case BottomCenter: + p.X = r.UR.X - r.Width()/2 - w/2 + p.Y = r.LL.Y + + case BottomRight: + p.X = r.UR.X - w + p.Y = r.LL.Y + } + + return p +} + +func boxByDim(boxName string, b *Box, d Dict, parent *Rectangle) *Rectangle { + w := b.Dim.Width + if w < 1 { + w *= parent.Width() + } + h := b.Dim.Height + if h < 1 { + h *= parent.Height() + } + ll := boxLowerLeftCorner(parent, w, h, b.Pos) + r := RectForWidthAndHeight(ll.X+float64(b.Dx), ll.Y+float64(b.Dy), w, h) + d.Update(boxName, r.Array()) + return r +} + +func applyBox(boxName string, b *Box, d Dict, parent *Rectangle) *Rectangle { + if b.Rect != nil { + d.Update(boxName, b.Rect.Array()) + return b.Rect + } + + if b.Dim != nil { + return boxByDim(boxName, b, d, parent) + } + + mLeft, mRight, mTop, mBot := b.MLeft, b.MRight, b.MTop, b.MBot + if -1 < b.MLeft && b.MLeft < 1 { + // Margins relative to media box + mLeft *= parent.Width() + mRight *= parent.Width() + mBot *= parent.Height() + mTop *= parent.Height() + } + xmin := parent.LL.X + mLeft + ymin := parent.LL.Y + mBot + xmax := parent.UR.X - mRight + ymax := parent.UR.Y - mTop + r := Rect(xmin, ymin, xmax, ymax) + d.Update(boxName, r.Array()) + if boxName != "CropBox" { + return r + } + + if xmin < parent.LL.X || ymin < parent.LL.Y || xmax > parent.UR.X || ymax > parent.UR.Y { + // Expand media box. + if xmin < parent.LL.X { + parent.LL.X = xmin + } + if xmax > parent.UR.X { + parent.UR.X = xmax + } + if ymin < parent.LL.Y { + parent.LL.Y = ymin + } + if xmax > parent.UR.X { + parent.UR.X = xmax + } + if ymax > parent.UR.Y { + parent.UR.Y = ymax + } + d.Update("MediaBox", parent.Array()) + } + return r +} + +type boxes struct { + mediaBox, cropBox, trimBox, bleedBox, artBox *Rectangle +} + +func applyBoxDefinitions(d Dict, pb *PageBoundaries, b *boxes) { + parentBox := b.mediaBox + if pb.Media != nil { + //fmt.Println("add mb") + b.mediaBox = applyBox("MediaBox", pb.Media, d, parentBox) + } + + if pb.Crop != nil { + //fmt.Println("add cb") + b.cropBox = applyBox("CropBox", pb.Crop, d, parentBox) + } + + if b.cropBox != nil { + parentBox = b.cropBox + } + if pb.Trim != nil && pb.Trim.RefBox == "" { + //fmt.Println("add tb") + b.trimBox = applyBox("TrimBox", pb.Trim, d, parentBox) + } + + if pb.Bleed != nil && pb.Bleed.RefBox == "" { + //fmt.Println("add bb") + b.bleedBox = applyBox("BleedBox", pb.Bleed, d, parentBox) + } + + if pb.Art != nil && pb.Art.RefBox == "" { + //fmt.Println("add ab") + b.artBox = applyBox("ArtBox", pb.Art, d, parentBox) + } +} + +func updateTrimBox(d Dict, trimBox *Box, b *boxes) { + var r *Rectangle + switch trimBox.RefBox { + case "media": + r = b.mediaBox + case "crop": + r = b.cropBox + case "bleed": + r = b.bleedBox + if r == nil { + r = b.cropBox + } + case "art": + r = b.artBox + if r == nil { + r = b.cropBox + } + } + d.Update("TrimBox", r.Array()) + b.trimBox = r +} + +func updateBleedBox(d Dict, bleedBox *Box, b *boxes) { + var r *Rectangle + switch bleedBox.RefBox { + case "media": + r = b.mediaBox + case "crop": + r = b.cropBox + case "trim": + r = b.trimBox + if r == nil { + r = b.cropBox + } + case "art": + r = b.artBox + if r == nil { + r = b.cropBox + } + } + d.Update("BleedBox", r.Array()) + b.bleedBox = r +} + +func updateArtBox(d Dict, artBox *Box, b *boxes) { + var r *Rectangle + switch artBox.RefBox { + case "media": + r = b.mediaBox + case "crop": + r = b.cropBox + case "trim": + r = b.trimBox + if r == nil { + r = b.cropBox + } + case "bleed": + r = b.bleedBox + if r == nil { + r = b.cropBox + } + } + d.Update("ArtBox", r.Array()) + b.artBox = r +} + +func applyBoxAssignments(d Dict, pb *PageBoundaries, b *boxes) { + if pb.Trim != nil && pb.Trim.RefBox != "" { + updateTrimBox(d, pb.Trim, b) + } + + if pb.Bleed != nil && pb.Bleed.RefBox != "" { + updateBleedBox(d, pb.Bleed, b) + } + + if pb.Art != nil && pb.Art.RefBox != "" { + updateArtBox(d, pb.Art, b) + } +} + +// AddPageBoundaries adds page boundaries specified by pb for selected pages. +func (ctx *Context) AddPageBoundaries(selectedPages IntSet, pb *PageBoundaries) error { + for k, v := range selectedPages { + if !v { + continue + } + d, inhPAttrs, err := ctx.PageDict(k, false) + if err != nil { + return err + } + mediaBox := inhPAttrs.mediaBox + cropBox := inhPAttrs.cropBox + + var trimBox *Rectangle + obj, found := d.Find("TrimBox") + if found { + a, err := ctx.DereferenceArray(obj) + if err != nil { + return err + } + if trimBox, err = rect(ctx.XRefTable, a); err != nil { + return err + } + } + + var bleedBox *Rectangle + obj, found = d.Find("BleedBox") + if found { + a, err := ctx.DereferenceArray(obj) + if err != nil { + return err + } + if bleedBox, err = rect(ctx.XRefTable, a); err != nil { + return err + } + } + + var artBox *Rectangle + obj, found = d.Find("ArtBox") + if found { + a, err := ctx.DereferenceArray(obj) + if err != nil { + return err + } + if artBox, err = rect(ctx.XRefTable, a); err != nil { + return err + } + } + + boxes := &boxes{mediaBox: mediaBox, cropBox: cropBox, trimBox: trimBox, bleedBox: bleedBox, artBox: artBox} + applyBoxDefinitions(d, pb, boxes) + applyBoxAssignments(d, pb, boxes) + } + return nil +} + +// Crop sets crop box for selected pages to b. +func (ctx *Context) Crop(selectedPages IntSet, b *Box) error { + for k, v := range selectedPages { + if !v { + continue + } + d, inhPAttrs, err := ctx.PageDict(k, false) + if err != nil { + return err + } + applyBox("CropBox", b, d, inhPAttrs.mediaBox) + } + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/collect.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/collect.go new file mode 100644 index 0000000..88c8faa --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/collect.go @@ -0,0 +1,39 @@ +/* +Copyright 2020 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "github.com/pdfcpu/pdfcpu/pkg/log" +) + +// CollectPages creates a new PDF Context for a custom PDF page sequence of the PDF represented by ctx. +func CollectPages(ctx *Context, collectedPages []int) (*Context, error) { + + log.Debug.Printf("CollectPages %v\n", collectedPages) + + ctxDest, err := CreateContextWithXRefTable(nil, PaperSize["A4"]) + if err != nil { + return nil, err + } + + usePgCache := true + if err := AddPages(ctx, ctxDest, collectedPages, usePgCache); err != nil { + return nil, err + } + + return ctxDest, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/colorSpace.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/colorSpace.go new file mode 100644 index 0000000..720ad69 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/colorSpace.go @@ -0,0 +1,32 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +// PDF defines the following Color Spaces: +const ( + DeviceGrayCS = "DeviceGray" + DeviceRGBCS = "DeviceRGB" + DeviceCMYKCS = "DeviceCMYK" + CalGrayCS = "CalGray" + CalRGBCS = "CalRGB" + LabCS = "Lab" + ICCBasedCS = "ICCBased" + IndexedCS = "Indexed" + PatternCS = "Pattern" + SeparationCS = "Separation" + DeviceNCS = "DeviceN" +) diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/configuration.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/configuration.go new file mode 100644 index 0000000..d3a8262 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/configuration.go @@ -0,0 +1,344 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/pdfcpu/pdfcpu/internal/config" + "github.com/pdfcpu/pdfcpu/pkg/font" +) + +const ( + // ValidationStrict ensures 100% compliance with the spec (PDF 32000-1:2008). + ValidationStrict int = iota + + // ValidationRelaxed ensures PDF compliance based on frequently encountered validation errors. + ValidationRelaxed + + // ValidationNone bypasses validation. + ValidationNone +) + +const ( + + // StatsFileNameDefault is the standard stats filename. + StatsFileNameDefault = "stats.csv" + + // PermissionsAll enables all user access permission bits. + PermissionsAll int16 = -1 // 0xFFFF + + // PermissionsNone disables all user access permissions bits. + PermissionsNone int16 = -3901 // 0xF0C3 + +) + +// CommandMode specifies the operation being executed. +type CommandMode int + +// The available commands. +const ( + VALIDATE CommandMode = iota + OPTIMIZE + SPLIT + MERGECREATE + MERGEAPPEND + EXTRACTIMAGES + EXTRACTFONTS + EXTRACTPAGES + EXTRACTCONTENT + EXTRACTMETADATA + TRIM + ADDATTACHMENTS + ADDATTACHMENTSPORTFOLIO + REMOVEATTACHMENTS + EXTRACTATTACHMENTS + LISTATTACHMENTS + SETPERMISSIONS + LISTPERMISSIONS + ENCRYPT + DECRYPT + CHANGEUPW + CHANGEOPW + ADDWATERMARKS + REMOVEWATERMARKS + IMPORTIMAGES + INSERTPAGESBEFORE + INSERTPAGESAFTER + REMOVEPAGES + ROTATE + NUP + INFO + CHEATSHEETSFONTS + INSTALLFONTS + LISTFONTS + LISTKEYWORDS + ADDKEYWORDS + REMOVEKEYWORDS + LISTPROPERTIES + ADDPROPERTIES + REMOVEPROPERTIES + COLLECT + CROP + LISTBOXES + ADDBOXES + REMOVEBOXES +) + +// Configuration of a Context. +type Configuration struct { + Path string + + // Enables PDF V1.5 compatible processing of object streams, xref streams, hybrid PDF files. + Reader15 bool + + // Enables decoding of all streams (fontfiles, images..) for logging purposes. + DecodeAllStreams bool + + // Validate against ISO-32000: strict or relaxed + ValidationMode int + + // End of line char sequence for writing. + Eol string + + // Turns on object stream generation. + // A signal for compressing any new non-stream-object into an object stream. + // true enforces WriteXRefStream to true. + // false does not prevent xRefStream generation. + WriteObjectStream bool + + // Switches between xRefSection (<=V1.4) and objectStream/xRefStream (>=V1.5) writing. + WriteXRefStream bool + + // Turns on stats collection. + // TODO Decision - unused. + CollectStats bool + + // A CSV-filename holding the statistics. + StatsFileName string + + // Supplied user password + UserPW string + UserPWNew *string + + // Supplied owner password + OwnerPW string + OwnerPWNew *string + + // EncryptUsingAES ensures AES encryption. + // true: AES encryption + // false: RC4 encryption. + EncryptUsingAES bool + + // AES:40,128,256 RC4:40,128 + EncryptKeyLength int + + // Supplied user access permissions, see Table 22 + Permissions int16 + + // Command being executed. + Cmd CommandMode + + // Display unit in effect. + Unit DisplayUnit +} + +// ConfigPath defines the location of pdfcpu's configuration directory. +// If set to a file path, pdfcpu will ensure the config dir at this location. +// Other possible values: +// default: Ensure config dir at default location +// disable: Disable config dir usage +var ConfigPath string = "default" + +var loadedDefaultConfig *Configuration + +func generateConfigFile(fileName string) error { + if err := ioutil.WriteFile(fileName, config.ConfigFileBytes, os.ModePerm); err != nil { + return err + } + loadedDefaultConfig = newDefaultConfiguration() + loadedDefaultConfig.Path = fileName + return nil +} + +func ensureConfigFileAt(path string) error { + // Accept config.yml and config.yaml + f, err := os.Open(path) + if err != nil { + // Create path/pdfcpu/config.yml + //fmt.Printf("writing %s ..\n", path) + return generateConfigFile(path) + } + defer f.Close() + // Load configuration into loadedDefaultConfig. + //fmt.Printf("loading %s ...\n", path) + return parseConfigFile(f, path) +} + +// EnsureDefaultConfigAt tries to load the default configuration from path. +// If path/pdfcpu/config.yaml is not found, it will be created. +func EnsureDefaultConfigAt(path string) error { + configDir := filepath.Join(path, "pdfcpu") + font.UserFontDir = filepath.Join(configDir, "fonts") + if err := os.MkdirAll(font.UserFontDir, os.ModePerm); err != nil { + return err + } + if err := ensureConfigFileAt(filepath.Join(configDir, "config.yml")); err != nil { + return err + } + //fmt.Println(loadedDefaultConfig) + return font.LoadUserFonts() +} + +func newDefaultConfiguration() *Configuration { + // NOTE: pdfcpu/internal/config/config.yml must be updated whenever the default configuration changes. + return &Configuration{ + Reader15: true, + DecodeAllStreams: false, + ValidationMode: ValidationRelaxed, + Eol: EolLF, + WriteObjectStream: true, + WriteXRefStream: true, + EncryptUsingAES: true, + EncryptKeyLength: 256, + Permissions: PermissionsNone, + } +} + +// NewDefaultConfiguration returns the default pdfcpu configuration. +func NewDefaultConfiguration() *Configuration { + if loadedDefaultConfig != nil { + c := *loadedDefaultConfig + return &c + } + if ConfigPath != "disable" { + path, err := os.UserConfigDir() + if err != nil { + path = os.TempDir() + } + if err = EnsureDefaultConfigAt(path); err == nil { + c := *loadedDefaultConfig + return &c + } + fmt.Fprintf(os.Stderr, "pdfcpu: config dir problem: %v\n", err) + os.Exit(1) + } + return newDefaultConfiguration() +} + +// NewAESConfiguration returns a default configuration for AES encryption. +func NewAESConfiguration(userPW, ownerPW string, keyLength int) *Configuration { + c := NewDefaultConfiguration() + c.UserPW = userPW + c.OwnerPW = ownerPW + c.EncryptUsingAES = true + c.EncryptKeyLength = keyLength + return c +} + +// NewRC4Configuration returns a default configuration for RC4 encryption. +func NewRC4Configuration(userPW, ownerPW string, keyLength int) *Configuration { + c := NewDefaultConfiguration() + c.UserPW = userPW + c.OwnerPW = ownerPW + c.EncryptUsingAES = false + c.EncryptKeyLength = keyLength + return c +} + +func (c Configuration) String() string { + path := "default" + if len(c.Path) > 0 { + path = c.Path + } + return fmt.Sprintf("pdfcpu configuration:\n"+ + "Path: %s\n"+ + "Reader15: %t\n"+ + "DecodeAllStreams: %t\n"+ + "ValidationMode: %s\n"+ + "Eol: %s\n"+ + "WriteObjectStream: %t\n"+ + "WriteXrefStream: %t\n"+ + "EncryptUsingAES: %t\n"+ + "EncryptKeyLength: %d\n"+ + "Permissions: %d\n"+ + "Unit : %s\n", + path, + c.Reader15, + c.DecodeAllStreams, + c.ValidationModeString(), + c.EolString(), + c.WriteObjectStream, + c.WriteXRefStream, + c.EncryptUsingAES, + c.EncryptKeyLength, + c.Permissions, + c.UnitString()) +} + +// EolString returns a string rep for the eol in effect. +func (c *Configuration) EolString() string { + var s string + switch c.Eol { + case EolLF: + s = "EolLF" + case EolCR: + s = "EolCR" + case EolCRLF: + s = "EolCRLF" + } + return s +} + +// ValidationModeString returns a string rep for the validation mode in effect. +func (c *Configuration) ValidationModeString() string { + if c.ValidationMode == ValidationStrict { + return "strict" + } + if c.ValidationMode == ValidationRelaxed { + return "relaxed" + } + return "none" +} + +// UnitString returns a string rep for the display unit in effect. +func (c *Configuration) UnitString() string { + var s string + switch c.Unit { + case POINTS: + s = "points" + case INCHES: + s = "inches" + case CENTIMETRES: + s = "cm" + case MILLIMETRES: + s = "mm" + } + return s +} + +// ApplyReducedFeatureSet returns true if complex entries like annotations shall not be written. +func (c *Configuration) ApplyReducedFeatureSet() bool { + switch c.Cmd { + case SPLIT, TRIM, EXTRACTPAGES, MERGECREATE, MERGEAPPEND, IMPORTIMAGES: + return true + } + return false +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/context.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/context.go new file mode 100644 index 0000000..6e8d5e2 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/context.go @@ -0,0 +1,725 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bufio" + "fmt" + "io" + "os" + "sort" + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/log" +) + +// Context represents an environment for processing PDF files. +type Context struct { + *Configuration + *XRefTable + Read *ReadContext + Optimize *OptimizationContext + Write *WriteContext + writingPages bool // true, when writing page dicts. + dest bool // true when writing a destination within a page. +} + +// NewContext initializes a new Context. +func NewContext(rs io.ReadSeeker, conf *Configuration) (*Context, error) { + + if conf == nil { + conf = NewDefaultConfiguration() + } + + rdCtx, err := newReadContext(rs) + if err != nil { + return nil, err + } + + ctx := &Context{ + conf, + newXRefTable(conf.ValidationMode), + rdCtx, + newOptimizationContext(), + NewWriteContext(conf.Eol), + false, + false, + } + + return ctx, nil +} + +// ResetWriteContext prepares an existing WriteContext for a new file to be written. +func (ctx *Context) ResetWriteContext() { + ctx.Write = NewWriteContext(ctx.Write.Eol) +} + +func (rc *ReadContext) logReadContext(logStr *[]string) { + if rc.UsingObjectStreams { + *logStr = append(*logStr, "using object streams\n") + } + if rc.UsingXRefStreams { + *logStr = append(*logStr, "using xref streams\n") + } + if rc.Linearized { + *logStr = append(*logStr, "is linearized file\n") + } + if rc.Hybrid { + *logStr = append(*logStr, "is hybrid reference file\n") + } +} + +func (ctx *Context) String() string { + + var logStr []string + + logStr = append(logStr, "*************************************************************************************************\n") + logStr = append(logStr, fmt.Sprintf("HeaderVersion: %s\n", ctx.HeaderVersion)) + + if ctx.RootVersion != nil { + logStr = append(logStr, fmt.Sprintf("RootVersion: %s\n", ctx.RootVersion)) + } + + logStr = append(logStr, fmt.Sprintf("has %d pages\n", ctx.PageCount)) + + ctx.Read.logReadContext(&logStr) + + if ctx.Tagged { + logStr = append(logStr, "is tagged file\n") + } + + logStr = append(logStr, "XRefTable:\n") + logStr = append(logStr, fmt.Sprintf(" Size: %d\n", *ctx.XRefTable.Size)) + logStr = append(logStr, fmt.Sprintf(" Root object: %s\n", *ctx.Root)) + + if ctx.Info != nil { + logStr = append(logStr, fmt.Sprintf(" Info object: %s\n", *ctx.Info)) + } + + if ctx.ID != nil { + logStr = append(logStr, fmt.Sprintf(" ID object: %s\n", ctx.ID)) + } + + if ctx.Encrypt != nil { + logStr = append(logStr, fmt.Sprintf(" Encrypt object: %s\n", *ctx.Encrypt)) + } + + if ctx.AdditionalStreams != nil && len(*ctx.AdditionalStreams) > 0 { + + var objectNumbers []string + for _, k := range *ctx.AdditionalStreams { + indRef, _ := k.(IndirectRef) + objectNumbers = append(objectNumbers, fmt.Sprintf("%d", int(indRef.ObjectNumber))) + } + sort.Strings(objectNumbers) + + logStr = append(logStr, fmt.Sprintf(" AdditionalStreams: %s\n\n", strings.Join(objectNumbers, ","))) + } + + logStr = append(logStr, fmt.Sprintf("XRefTable with %d entres:\n", len(ctx.Table))) + + // Print sorted object list. + logStr = ctx.list(logStr) + + // Print free list. + logStr, err := ctx.freeList(logStr) + if err != nil { + log.Info.Fatalln(err) + } + + // Print list of any missing objects. + if len(ctx.XRefTable.Table) < *ctx.XRefTable.Size { + if count, mstr := ctx.MissingObjects(); count > 0 { + logStr = append(logStr, fmt.Sprintf("%d missing objects: %s\n", count, *mstr)) + } + } + + logStr = append(logStr, fmt.Sprintf("\nTotal pages: %d\n", ctx.PageCount)) + logStr = ctx.Optimize.collectFontInfo(logStr) + logStr = ctx.Optimize.collectImageInfo(logStr) + logStr = append(logStr, "\n") + + return strings.Join(logStr, "") +} + +func (ctx *Context) unit() string { + u := "points" + switch ctx.Unit { + case INCHES: + u = "inches" + case CENTIMETRES: + u = "cm" + case MILLIMETRES: + u = "mm" + } + return u +} + +func (ctx *Context) convertToUnit(d Dim) Dim { + switch ctx.Unit { + case INCHES: + return d.ToInches() + case CENTIMETRES: + return d.ToCentimetres() + case MILLIMETRES: + return d.ToMillimetres() + } + return d +} + +func (ctx *Context) addKeywordsToInfoDigest(ss *[]string) error { + if len(ctx.Keywords) == 0 { + return nil + } + kwl, err := KeywordsList(ctx.XRefTable) + if err != nil { + return err + } + for i, l := range kwl { + if i == 0 { + *ss = append(*ss, fmt.Sprintf("%20s: %s", "Keywords", l)) + continue + } + *ss = append(*ss, fmt.Sprintf("%20s %s", "", l)) + } + return nil +} + +func (ctx *Context) addPropertiesToInfoDigest(ss *[]string) error { + if len(ctx.Properties) == 0 { + return nil + } + first := true + for k, v := range ctx.Properties { + if first { + *ss = append(*ss, fmt.Sprintf("%20s: %s = %s", "Properties", k, v)) + first = false + continue + } + *ss = append(*ss, fmt.Sprintf("%20s %s = %s", "", k, v)) + } + return nil +} + +func (ctx *Context) addPermissionsToInfoDigest(ss *[]string) { + l := Permissions(ctx) + if len(l) == 1 { + *ss = append(*ss, fmt.Sprintf("%20s: %s", "Permissions", l[0])) + } else { + *ss = append(*ss, fmt.Sprintf("%20s:", "Permissions")) + for _, s := range l { + *ss = append(*ss, s) + } + } +} + +func (ctx *Context) addAttachmentsToInfoDigest(ss *[]string) error { + aa, err := ctx.ListAttachments() + if err != nil { + return err + } + if len(aa) == 0 { + return nil + } + + var list []string + for _, a := range aa { + s := a.FileName + if a.Desc != "" { + s = fmt.Sprintf("%s (%s)", s, a.Desc) + } + list = append(list, s) + } + sort.Strings(list) + + for i, s := range list { + if i == 0 { + *ss = append(*ss, fmt.Sprintf("%20s: %s", "Attachments", s)) + continue + } + *ss = append(*ss, fmt.Sprintf("%20s %s,", "", s)) + } + + return nil +} + +// ReadContext represents the context for reading a PDF file. +type ReadContext struct { + FileName string // Input PDF-File. + FileSize int64 // Input file size. + rs io.ReadSeeker // Input read seeker. + EolCount int // 1 or 2 characters used for eol. + BinaryTotalSize int64 // total stream data + BinaryImageSize int64 // total image stream data + BinaryFontSize int64 // total font stream data (fontfiles) + BinaryImageDuplSize int64 // total obsolet image stream data after optimization + BinaryFontDuplSize int64 // total obsolet font stream data after optimization + Linearized bool // File is linearized. + Hybrid bool // File is a hybrid PDF file. + UsingObjectStreams bool // File is using object streams. + ObjectStreams IntSet // All object numbers of any object streams found which need to be decoded. + UsingXRefStreams bool // File is using xref streams. + XRefStreams IntSet // All object numbers of any xref streams found. +} + +func newReadContext(rs io.ReadSeeker) (*ReadContext, error) { + + rdCtx := &ReadContext{ + rs: rs, + ObjectStreams: IntSet{}, + XRefStreams: IntSet{}, + } + + fileSize, err := rs.Seek(0, io.SeekEnd) + if err != nil { + return nil, err + } + rdCtx.FileSize = fileSize + + return rdCtx, nil +} + +// IsObjectStreamObject returns true if object i is a an object stream. +// All compressed objects are object streams. +func (rc *ReadContext) IsObjectStreamObject(i int) bool { + return rc.ObjectStreams[i] +} + +// ObjectStreamsString returns a formatted string and the number of object stream objects. +func (rc *ReadContext) ObjectStreamsString() (int, string) { + + var objs []int + for k := range rc.ObjectStreams { + if rc.ObjectStreams[k] { + objs = append(objs, k) + } + } + sort.Ints(objs) + + var objStreams []string + for _, i := range objs { + objStreams = append(objStreams, fmt.Sprintf("%d", i)) + } + + return len(objStreams), strings.Join(objStreams, ",") +} + +// IsXRefStreamObject returns true if object #i is a an xref stream. +func (rc *ReadContext) IsXRefStreamObject(i int) bool { + return rc.XRefStreams[i] +} + +// XRefStreamsString returns a formatted string and the number of xref stream objects. +func (rc *ReadContext) XRefStreamsString() (int, string) { + + var objs []int + for k := range rc.XRefStreams { + if rc.XRefStreams[k] { + objs = append(objs, k) + } + } + sort.Ints(objs) + + var xrefStreams []string + for _, i := range objs { + xrefStreams = append(xrefStreams, fmt.Sprintf("%d", i)) + } + + return len(xrefStreams), strings.Join(xrefStreams, ",") +} + +// LogStats logs stats for read file. +func (rc *ReadContext) LogStats(optimized bool) { + + log := log.Stats + + textSize := rc.FileSize - rc.BinaryTotalSize // = non binary content = non stream data + + log.Println("Original:") + log.Printf("File size : %s (%d bytes)\n", ByteSize(rc.FileSize), rc.FileSize) + log.Printf("Total binary data : %s (%d bytes) %4.1f%%\n", ByteSize(rc.BinaryTotalSize), rc.BinaryTotalSize, float32(rc.BinaryTotalSize)/float32(rc.FileSize)*100) + log.Printf("Total other data : %s (%d bytes) %4.1f%%\n\n", ByteSize(textSize), textSize, float32(textSize)/float32(rc.FileSize)*100) + + // Only when optimizing we get details about resource data usage. + if optimized { + + // Image stream data of original file. + binaryImageSize := rc.BinaryImageSize + rc.BinaryImageDuplSize + + // Font stream data of original file. (just font files) + binaryFontSize := rc.BinaryFontSize + rc.BinaryFontDuplSize + + // Content stream data, other font related stream data. + binaryOtherSize := rc.BinaryTotalSize - binaryImageSize - binaryFontSize + + log.Println("Breakup of binary data:") + log.Printf("images : %s (%d bytes) %4.1f%%\n", ByteSize(binaryImageSize), binaryImageSize, float32(binaryImageSize)/float32(rc.BinaryTotalSize)*100) + log.Printf("fonts : %s (%d bytes) %4.1f%%\n", ByteSize(binaryFontSize), binaryFontSize, float32(binaryFontSize)/float32(rc.BinaryTotalSize)*100) + log.Printf("other : %s (%d bytes) %4.1f%%\n\n", ByteSize(binaryOtherSize), binaryOtherSize, float32(binaryOtherSize)/float32(rc.BinaryTotalSize)*100) + } +} + +// ReadFileSize returns the size of the input file, if there is one. +func (rc *ReadContext) ReadFileSize() int { + if rc == nil { + return 0 + } + return int(rc.FileSize) +} + +// OptimizationContext represents the context for the optimiziation of a PDF file. +type OptimizationContext struct { + + // Font section + PageFonts []IntSet // For each page a registry of font object numbers. + FontObjects map[int]*FontObject // FontObject lookup table by font object number. + Fonts map[string][]int // All font object numbers registered for a font name. + DuplicateFonts map[int]Dict // Registry of duplicate font dicts. + DuplicateFontObjs IntSet // The set of objects that represents the union of the object graphs of all duplicate font dicts. + + // Image section + PageImages []IntSet // For each page a registry of image object numbers. + ImageObjects map[int]*ImageObject // ImageObject lookup table by image object number. + DuplicateImages map[int]*StreamDict // Registry of duplicate image dicts. + DuplicateImageObjs IntSet // The set of objects that represents the union of the object graphs of all duplicate image dicts. + + DuplicateInfoObjects IntSet // Possible result of manual info dict modification. + NonReferencedObjs []int // Objects that are not referenced. + + Cache map[int]bool // For visited objects during optimization. + NullObjNr *int // objNr of a regular null object, to be used for fixing references to free objects. +} + +func newOptimizationContext() *OptimizationContext { + return &OptimizationContext{ + FontObjects: map[int]*FontObject{}, + Fonts: map[string][]int{}, + DuplicateFonts: map[int]Dict{}, + DuplicateFontObjs: IntSet{}, + ImageObjects: map[int]*ImageObject{}, + DuplicateImages: map[int]*StreamDict{}, + DuplicateImageObjs: IntSet{}, + DuplicateInfoObjects: IntSet{}, + Cache: map[int]bool{}, + } +} + +// IsDuplicateFontObject returns true if object #i is a duplicate font object. +func (oc *OptimizationContext) IsDuplicateFontObject(i int) bool { + return oc.DuplicateFontObjs[i] +} + +// DuplicateFontObjectsString returns a formatted string and the number of objs. +func (oc *OptimizationContext) DuplicateFontObjectsString() (int, string) { + + var objs []int + for k := range oc.DuplicateFontObjs { + if oc.DuplicateFontObjs[k] { + objs = append(objs, k) + } + } + sort.Ints(objs) + + var dupFonts []string + for _, i := range objs { + dupFonts = append(dupFonts, fmt.Sprintf("%d", i)) + } + + return len(dupFonts), strings.Join(dupFonts, ",") +} + +// IsDuplicateImageObject returns true if object #i is a duplicate image object. +func (oc *OptimizationContext) IsDuplicateImageObject(i int) bool { + return oc.DuplicateImageObjs[i] +} + +// DuplicateImageObjectsString returns a formatted string and the number of objs. +func (oc *OptimizationContext) DuplicateImageObjectsString() (int, string) { + + var objs []int + for k := range oc.DuplicateImageObjs { + if oc.DuplicateImageObjs[k] { + objs = append(objs, k) + } + } + sort.Ints(objs) + + var dupImages []string + for _, i := range objs { + dupImages = append(dupImages, fmt.Sprintf("%d", i)) + } + + return len(dupImages), strings.Join(dupImages, ",") +} + +// IsDuplicateInfoObject returns true if object #i is a duplicate info object. +func (oc *OptimizationContext) IsDuplicateInfoObject(i int) bool { + return oc.DuplicateInfoObjects[i] +} + +// DuplicateInfoObjectsString returns a formatted string and the number of objs. +func (oc *OptimizationContext) DuplicateInfoObjectsString() (int, string) { + + var objs []int + for k := range oc.DuplicateInfoObjects { + if oc.DuplicateInfoObjects[k] { + objs = append(objs, k) + } + } + sort.Ints(objs) + + var dupInfos []string + for _, i := range objs { + dupInfos = append(dupInfos, fmt.Sprintf("%d", i)) + } + + return len(dupInfos), strings.Join(dupInfos, ",") +} + +// NonReferencedObjsString returns a formatted string and the number of objs. +func (oc *OptimizationContext) NonReferencedObjsString() (int, string) { + + var s []string + for _, o := range oc.NonReferencedObjs { + s = append(s, fmt.Sprintf("%d", o)) + } + + return len(oc.NonReferencedObjs), strings.Join(s, ",") +} + +// Prepare info gathered about font usage in form of a string array. +func (oc *OptimizationContext) collectFontInfo(logStr []string) []string { + + // Print available font info. + if len(oc.Fonts) == 0 || len(oc.PageFonts) == 0 { + return append(logStr, "No font info available.\n") + } + + fontHeader := "obj prefix Fontname Subtype Encoding Embedded ResourceIds\n" + + // Log fonts usage per page. + for i, fontObjectNumbers := range oc.PageFonts { + + if len(fontObjectNumbers) == 0 { + continue + } + + logStr = append(logStr, fmt.Sprintf("\nFonts for page %d:\n", i+1)) + logStr = append(logStr, fontHeader) + + var objectNumbers []int + for k := range fontObjectNumbers { + objectNumbers = append(objectNumbers, k) + } + sort.Ints(objectNumbers) + + for _, objectNumber := range objectNumbers { + fontObject := oc.FontObjects[objectNumber] + logStr = append(logStr, fmt.Sprintf("#%-6d %s", objectNumber, fontObject)) + } + } + + // Log all fonts sorted by object number. + logStr = append(logStr, fmt.Sprintf("\nFontobjects:\n")) + logStr = append(logStr, fontHeader) + + var objectNumbers []int + for k := range oc.FontObjects { + objectNumbers = append(objectNumbers, k) + } + sort.Ints(objectNumbers) + + for _, objectNumber := range objectNumbers { + fontObject := oc.FontObjects[objectNumber] + logStr = append(logStr, fmt.Sprintf("#%-6d %s", objectNumber, fontObject)) + } + + // Log all fonts sorted by fontname. + logStr = append(logStr, fmt.Sprintf("\nFonts:\n")) + logStr = append(logStr, fontHeader) + + var fontNames []string + for k := range oc.Fonts { + fontNames = append(fontNames, k) + } + sort.Strings(fontNames) + + for _, fontName := range fontNames { + for _, objectNumber := range oc.Fonts[fontName] { + fontObject := oc.FontObjects[objectNumber] + logStr = append(logStr, fmt.Sprintf("#%-6d %s", objectNumber, fontObject)) + } + } + + logStr = append(logStr, fmt.Sprintf("\nDuplicate Fonts:\n")) + + // Log any duplicate fonts. + if len(oc.DuplicateFonts) > 0 { + + var objectNumbers []int + for k := range oc.DuplicateFonts { + objectNumbers = append(objectNumbers, k) + } + sort.Ints(objectNumbers) + + var f []string + + for _, i := range objectNumbers { + f = append(f, fmt.Sprintf("%d", i)) + } + + logStr = append(logStr, strings.Join(f, ",")) + } + + return append(logStr, "\n") +} + +// Prepare info gathered about image usage in form of a string array. +func (oc *OptimizationContext) collectImageInfo(logStr []string) []string { + + // Print available image info. + if len(oc.ImageObjects) == 0 { + return append(logStr, "\nNo image info available.\n") + } + + imageHeader := "obj ResourceIds\n" + + // Log images per page. + for i, imageObjectNumbers := range oc.PageImages { + + if len(imageObjectNumbers) == 0 { + continue + } + + logStr = append(logStr, fmt.Sprintf("\nImages for page %d:\n", i+1)) + logStr = append(logStr, imageHeader) + + var objectNumbers []int + for k := range imageObjectNumbers { + objectNumbers = append(objectNumbers, k) + } + sort.Ints(objectNumbers) + + for _, objectNumber := range objectNumbers { + imageObject := oc.ImageObjects[objectNumber] + logStr = append(logStr, fmt.Sprintf("#%-6d %s\n", objectNumber, imageObject.ResourceNamesString())) + } + } + + // Log all images sorted by object number. + logStr = append(logStr, fmt.Sprintf("\nImageobjects:\n")) + logStr = append(logStr, imageHeader) + + var objectNumbers []int + for k := range oc.ImageObjects { + objectNumbers = append(objectNumbers, k) + } + sort.Ints(objectNumbers) + + for _, objectNumber := range objectNumbers { + imageObject := oc.ImageObjects[objectNumber] + logStr = append(logStr, fmt.Sprintf("#%-6d %s\n", objectNumber, imageObject.ResourceNamesString())) + } + + logStr = append(logStr, fmt.Sprintf("\nDuplicate Images:\n")) + + // Log any duplicate images. + if len(oc.DuplicateImages) > 0 { + + var objectNumbers []int + for k := range oc.DuplicateImages { + objectNumbers = append(objectNumbers, k) + } + sort.Ints(objectNumbers) + + var f []string + + for _, i := range objectNumbers { + f = append(f, fmt.Sprintf("%d", i)) + } + + logStr = append(logStr, strings.Join(f, ",")) + } + + return logStr +} + +// WriteContext represents the context for writing a PDF file. +type WriteContext struct { + + // The PDF-File which gets generated. + *bufio.Writer // A writer associated with Fp. + Fp *os.File // A file pointer needed for detecting FileSize. + FileSize int64 // The size of the written file. + DirName string // The output directory. + FileName string // The output file name. + SelectedPages IntSet // For split, trim and extract. + BinaryTotalSize int64 // total stream data, counts 100% all stream data written. + BinaryImageSize int64 // total image stream data written = Read.BinaryImageSize. + BinaryFontSize int64 // total font stream data (fontfiles) = copy of Read.BinaryFontSize. + Table map[int]int64 // object write offsets + Offset int64 // current write offset + WriteToObjectStream bool // if true start to embed objects into object streams and obey ObjectStreamMaxObjects. + CurrentObjStream *int // if not nil, any new non-stream-object gets added to the object stream with this object number. + Eol string // end of line char sequence +} + +// NewWriteContext returns a new WriteContext. +func NewWriteContext(eol string) *WriteContext { + return &WriteContext{SelectedPages: IntSet{}, Table: map[int]int64{}, Eol: eol} +} + +// SetWriteOffset saves the current write offset to the PDFDestination. +func (wc *WriteContext) SetWriteOffset(objNumber int) { + wc.Table[objNumber] = wc.Offset +} + +// HasWriteOffset returns true if an object has already been written to PDFDestination. +func (wc *WriteContext) HasWriteOffset(objNumber int) bool { + _, found := wc.Table[objNumber] + return found +} + +// LogStats logs stats for written file. +func (wc *WriteContext) LogStats() { + + fileSize := wc.FileSize + binaryTotalSize := wc.BinaryTotalSize // stream data + textSize := fileSize - binaryTotalSize // non stream data + + binaryImageSize := wc.BinaryImageSize + binaryFontSize := wc.BinaryFontSize + binaryOtherSize := binaryTotalSize - binaryImageSize - binaryFontSize // content streams + + log.Stats.Println("Optimized:") + log.Stats.Printf("File size : %s (%d bytes)\n", ByteSize(fileSize), fileSize) + log.Stats.Printf("Total binary data : %s (%d bytes) %4.1f%%\n", ByteSize(binaryTotalSize), binaryTotalSize, float32(binaryTotalSize)/float32(fileSize)*100) + log.Stats.Printf("Total other data : %s (%d bytes) %4.1f%%\n\n", ByteSize(textSize), textSize, float32(textSize)/float32(fileSize)*100) + + log.Stats.Println("Breakup of binary data:") + log.Stats.Printf("images : %s (%d bytes) %4.1f%%\n", ByteSize(binaryImageSize), binaryImageSize, float32(binaryImageSize)/float32(binaryTotalSize)*100) + log.Stats.Printf("fonts : %s (%d bytes) %4.1f%%\n", ByteSize(binaryFontSize), binaryFontSize, float32(binaryFontSize)/float32(binaryTotalSize)*100) + log.Stats.Printf("other : %s (%d bytes) %4.1f%%\n\n", ByteSize(binaryOtherSize), binaryOtherSize, float32(binaryOtherSize)/float32(binaryTotalSize)*100) +} + +// WriteEol writes an end of line sequence. +func (wc *WriteContext) WriteEol() error { + + _, err := wc.WriteString(wc.Eol) + + return err +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/create.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/create.go new file mode 100644 index 0000000..fe7021b --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/create.go @@ -0,0 +1,862 @@ +/* +Copyright 2020 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bytes" + "fmt" + "math" + "strconv" + "strings" + "unicode/utf8" + + "github.com/pdfcpu/pdfcpu/pkg/font" + "github.com/pdfcpu/pdfcpu/pkg/types" +) + +// HAlignment represents the horizontal alignment of text. +type HAlignment int + +// These are the options for horizontal aligned text. +const ( + AlignLeft HAlignment = iota + AlignCenter + AlignRight + AlignJustify +) + +// VAlignment represents the vertical alignment of text. +type VAlignment int + +// These are the options for vertical aligned text. +const ( + AlignBaseline VAlignment = iota + AlignTop + AlignMiddle + AlignBottom +) + +// LineJoinStyle represents the shape to be used at the corners of paths that are stroked (see 8.4.3.4) +type LineJoinStyle int + +// Render mode +const ( + LJMiter LineJoinStyle = iota + LJRound + LJBevel +) + +// TextDescriptor contains all attributes needed for rendering a text column in PDF user space. +type TextDescriptor struct { + Text string // A multi line string using \n for line breaks. + FontName string // Corefont name to be used. + FontKey string // Resource id registered for FontName. + FontSize int // Fontsize in points. + X, Y float64 // Position of first char's baseline. + Dx, Dy float64 // Horizontal and vertical offsets for X,Y. + MTop, MBot float64 // Top and bottom margins applied to text bounding box. + MLeft, MRight float64 // Left and right margins applied to text bounding box. + MinHeight float64 // The minimum height of this text's bounding box. + Rotation float64 // 0..360 degree rotation angle. + ScaleAbs bool // Scaling type, true=absolute, false=relative to container dimensions. + Scale float64 // font scaling factor > 0 (<= 1 for relative scaling). + HAlign HAlignment // Horizontal text alignment. + VAlign VAlignment // Vertical text alignment. + RMode RenderMode // Text render mode + StrokeCol SimpleColor // Stroke color to be used for rendering text corresponding to RMode. + FillCol SimpleColor // Fill color to be used for rendering text corresponding to RMode. + ShowTextBB bool // Render bounding box including BackgroundCol, border and margins. + ShowBackground bool // Render background of bounding box using BackgroundCol. + BackgroundCol SimpleColor // Bounding box fill color. + ShowBorder bool // Render border using BorderCol, BorderWidth and BorderStyle. + BorderWidth float64 // Border width, visibility depends on ShowBorder. + BorderStyle LineJoinStyle // Border style, also visible if ShowBorder is false as long as ShowBackground is true. + BorderCol SimpleColor // Border color. + ParIndent bool // Indent first line of paragraphs or space between paragraphs. + ShowLineBB bool // Render line bounding boxes in black (for HAlign != AlignJustify only) + ShowMargins bool // Render all margins in light gray. + HairCross bool // Draw haircross at X,Y. +} + +// FontMap maps font resource ids to font names. +type FontMap map[string]string + +// EnsureKey registers fontName with corresponding font resource id. +func (fm FontMap) EnsureKey(fontName string) string { + for k, v := range fm { + if v == fontName { + return k + } + } + key := "F" + strconv.Itoa(len(fm)) + fm[key] = fontName + return key +} + +// Page represents rendered page content. +type Page struct { + MediaBox *Rectangle + Fm FontMap + Buf *bytes.Buffer +} + +// NewPage creates a page for a mediaBox. +func NewPage(mediaBox *Rectangle) Page { + return Page{MediaBox: mediaBox, Fm: FontMap{}, Buf: new(bytes.Buffer)} +} + +// NewPageWithBg creates a page for a mediaBox. +func NewPageWithBg(mediaBox *Rectangle, c SimpleColor) Page { + p := Page{MediaBox: mediaBox, Fm: FontMap{}, Buf: new(bytes.Buffer)} + FillRect(p.Buf, mediaBox, c) + return p +} + +func deltaAlignMiddle(fontName string, fontSize, lines int, mTop, mBot float64) float64 { + return -font.Ascent(fontName, fontSize) + (float64(lines)*font.LineHeight(fontName, fontSize)+mTop+mBot)/2 - mTop +} + +func deltaAlignTop(fontName string, fontSize int, mTop float64) float64 { + return -font.Ascent(fontName, fontSize) - mTop +} + +func deltaAlignBottom(fontName string, fontSize, lines int, mBot float64) float64 { + return -font.Ascent(fontName, fontSize) + float64(lines)*font.LineHeight(fontName, fontSize) + mBot +} + +var unicodeToCP1252 = map[rune]byte{ + 0x20AC: 128, // € Euro Sign Note: Width in metrics file is not correct! + 0x201A: 130, // ‚ Single Low-9 Quotation Mark + 0x0192: 131, // ƒ Latin Small Letter F with Hook + 0x201E: 132, // „ Double Low-9 Quotation Mark + 0x2026: 133, // … Horizontal Ellipsis + 0x2020: 134, // † Dagger + 0x2021: 135, // ‡ Double Dagger + 0x02C6: 136, // ˆ Modifier Letter Circumflex Accent + 0x2030: 137, // ‰ Per Mille Sign + 0x0160: 138, // Š Latin Capital Letter S with Caron + 0x2039: 139, // ‹ Single Left-Pointing Angle Quotation Mark + 0x0152: 140, // Œ Latin Capital Ligature Oe + 0x017D: 142, // Ž Latin Capital Letter Z with Caron + 0x2018: 145, // ‘ Left Single Quotation Mark + 0x2019: 146, // ’ Right Single Quotation Mark + 0x201C: 147, // “ Left Double Quotation Mark + 0x201D: 148, // ” Right Double Quotation Mark + 0x2022: 149, // • Bullet + 0x2013: 150, // – En Dash + 0x2014: 151, // — Em Dash + 0x02DC: 152, // ˜ Small Tilde + 0x2122: 153, // ™ Trade Mark Sign Emoji + 0x0161: 154, // š Latin Small Letter S with Caron + 0x203A: 155, // › Single Right-Pointing Angle Quotation Mark + 0x0153: 156, // œ Latin Small Ligature Oe + 0x017E: 158, // ž Latin Small Letter Z with Caron + 0x0178: 159, // Ÿ Latin Capital Letter Y with Diaeresis +} + +func decodeUTF8ToByte(s string) string { + var sb strings.Builder + for _, r := range s { + // Unicode => char code + if r <= 0xFF { + sb.WriteByte(byte(r)) + continue + } + if b, ok := unicodeToCP1252[r]; ok { + sb.WriteByte(b) + continue + } + sb.WriteByte(byte(0x20)) + } + return sb.String() +} + +// SetLineJoinStyle sets the line join style for stroking operations. +func SetLineJoinStyle(b *bytes.Buffer, s LineJoinStyle) { + b.WriteString(fmt.Sprintf("%d j ", s)) +} + +// SetLineWidth sets line width for stroking operations. +func SetLineWidth(b *bytes.Buffer, w float64) { + b.WriteString(fmt.Sprintf("%.2f w ", w)) +} + +// DrawLine draws the path from P to Q. +func DrawLine(b *bytes.Buffer, xp, yp, xq, yq float64) { + b.WriteString(fmt.Sprintf("%.2f %.2f m %.2f %.2f l s ", xp, yp, xq, yq)) +} + +// DrawRect strokes a rectangular path for r. +func DrawRect(b *bytes.Buffer, r *Rectangle) { + b.WriteString(fmt.Sprintf("%.2f %.2f %.2f %.2f re s ", r.LL.X, r.LL.Y, r.Width(), r.Height())) +} + +// DrawAndFillRect strokes and fills a rectangular path for r. +func DrawAndFillRect(b *bytes.Buffer, r *Rectangle) { + b.WriteString(fmt.Sprintf("%.2f %.2f %.2f %.2f re B ", r.LL.X, r.LL.Y, r.Width(), r.Height())) +} + +// SetFillColor sets the fill color. +func SetFillColor(bb *bytes.Buffer, c SimpleColor) { + bb.WriteString(fmt.Sprintf("%.2f %.2f %.2f rg ", c.R, c.G, c.B)) +} + +// SetStrokeColor sets the stroke color. +func SetStrokeColor(bb *bytes.Buffer, c SimpleColor) { + bb.WriteString(fmt.Sprintf("%.2f %.2f %.2f RG ", c.R, c.G, c.B)) +} + +// FillRect draws and fills a rectangle using r, g, b. +func FillRect(bb *bytes.Buffer, rect *Rectangle, c SimpleColor) { + SetFillColor(bb, c) + DrawAndFillRect(bb, rect) +} + +// DrawGrid draws an x * y grid on r using strokeCol and fillCol. +func DrawGrid(bb *bytes.Buffer, x, y int, r *Rectangle, strokeCol SimpleColor, fillCol *SimpleColor) { + SetLineWidth(bb, 0) + SetStrokeColor(bb, strokeCol) + if fillCol != nil { + FillRect(bb, r, *fillCol) + } + + s := r.Width() / float64(x) + for i := 0; i <= x; i++ { + x := r.LL.X + float64(i)*s + DrawLine(bb, x, r.LL.Y, x, r.UR.Y) + } + + s = r.Height() / float64(y) + for i := 0; i <= y; i++ { + y := r.LL.Y + float64(i)*s + DrawLine(bb, r.LL.X, y, r.UR.X, y) + } +} + +func calcBoundingBoxForRectAndPoint(r *Rectangle, p types.Point) *Rectangle { + llx, lly, urx, ury := r.LL.X, r.LL.Y, r.UR.X, r.UR.Y + if p.X < r.LL.X { + llx = p.X + } else if p.X > r.UR.X { + urx = p.X + } + if p.Y < r.LL.Y { + lly = p.Y + } else if p.Y > r.UR.Y { + ury = p.Y + } + return Rect(llx, lly, urx, ury) +} + +func calcBoundingBoxForRects(r1, r2 *Rectangle) *Rectangle { + if r1 == nil && r2 == nil { + return Rect(0, 0, 0, 0) + } + if r1 == nil { + return r2 + } + if r2 == nil { + return r1 + } + bbox := calcBoundingBoxForRectAndPoint(r1, r2.LL) + return calcBoundingBoxForRectAndPoint(bbox, r2.UR) +} + +func calcBoundingBoxForLines(lines []string, x, y float64, fontName string, fontSize int) (*Rectangle, string) { + var ( + box *Rectangle + maxLine string + maxWidth float64 + ) + // TODO Return error if lines == nil or empty. + for _, s := range lines { + bbox := calcBoundingBox(s, x, y, fontName, fontSize) + if bbox.Width() > maxWidth { + maxWidth = bbox.Width() + maxLine = s + } + box = calcBoundingBoxForRects(box, bbox) + y -= bbox.Height() + } + return box, maxLine +} + +func calcBoundingBoxJ(x, y, w, h, d float64, fontName string, fontSize int) *Rectangle { + y -= d + return Rect(x, y, x+w, y+h) +} + +func calcBoundingBoxForJLines(lines []string, x, y, w float64, fontName string, fontSize int) *Rectangle { + var box *Rectangle + h := font.LineHeight(fontName, fontSize) + d := math.Ceil(font.Descent(fontName, fontSize)) + // TODO Return error if lines == nil or empty. + for i := 0; i < len(lines); i++ { + bbox := calcBoundingBoxJ(x, y, w, h, d, fontName, fontSize) + box = calcBoundingBoxForRects(box, bbox) + y -= bbox.Height() + } + return box +} + +// DrawHairCross draw a haircross with origin x/y. +func DrawHairCross(buf *bytes.Buffer, x, y float64, r *Rectangle) { + x1, y1 := x, y + if x == 0 { + x1 = r.LL.X + r.Width()/2 + } + if y == 0 { + y1 = r.LL.Y + r.Height()/2 + } + SetLineWidth(buf, 0) + SetStrokeColor(buf, Black) + DrawLine(buf, r.LL.X, y1, r.LL.X+r.Width(), y1) // Horizontal line + DrawLine(buf, x1, r.LL.Y, x1, r.LL.Y+r.Height()) // Vertical line +} + +func prepBytes(s, fontName string) string { + if font.IsUserFont(fontName) { + ttf := font.UserFontMetrics[fontName] + bb := []byte{} + for _, r := range s { + gid, ok := ttf.Chars[uint32(r)] + if ok { + bb = append(bb, byte((gid>>8)&0xFF)) + bb = append(bb, byte(gid&0xFF)) + ttf.UsedGIDs[gid] = true + } + } + s = string(bb) + } + s1, _ := Escape(s) + return *s1 +} + +func writeStringToBuf(buf *bytes.Buffer, s string, x, y float64, strokeCol, fillCol SimpleColor, rm RenderMode, fontName string) { + s = prepBytes(s, fontName) + buf.WriteString(fmt.Sprintf("BT 0 Tw %.2f %.2f %.2f RG %.2f %.2f %.2f rg %.2f %.2f Td %d Tr (%s) Tj ET ", + strokeCol.R, strokeCol.G, strokeCol.B, fillCol.R, fillCol.G, fillCol.B, x, y, rm, s)) +} + +func setFont(b *bytes.Buffer, fontID string, fontSize float32) { + b.WriteString(fmt.Sprintf("BT /%s %.2f Tf ET ", fontID, fontSize)) +} + +func calcBoundingBox(s string, x, y float64, fontName string, fontSize int) *Rectangle { + w := font.TextWidth(s, fontName, fontSize) + h := font.LineHeight(fontName, fontSize) + y -= math.Ceil(font.Descent(fontName, fontSize)) + return Rect(x, y, x+w, y+h) +} + +func calcRotateTransformMatrix(rot, dx, dy float64, bb *Rectangle) matrix { + sin := math.Sin(float64(rot) * float64(degToRad)) + cos := math.Cos(float64(rot) * float64(degToRad)) + m1 := identMatrix + m1[0][0] = cos + m1[0][1] = sin + m1[1][0] = -sin + m1[1][1] = cos + m2 := identMatrix + m2[2][0] = bb.LL.X + bb.Width()/2 + sin*(bb.Height()/2) - cos*bb.Width()/2 + m2[2][1] = bb.LL.Y + bb.Height()/2 - cos*(bb.Height()/2) - sin*bb.Width()/2 + return m1.multiply(m2) +} + +func horAdjustBoundingBoxForLines(r, box *Rectangle, dx, dy float64, x, y *float64) { + if r.UR.X-box.LL.X < box.Width() { + dx -= box.Width() - (r.UR.X - box.LL.X) + *x += dx + box.Translate(dx, 0) + } else if box.LL.X < r.LL.X { + dx += r.LL.X - box.LL.X + *x += dx + box.Translate(dx, 0) + } + if r.UR.Y-box.LL.Y < box.Height() { + dy -= box.Height() - (r.UR.Y - box.LL.Y) + *y += dy + box.Translate(0, dy) + } else if box.LL.Y < r.LL.Y { + dy += r.LL.Y - box.LL.Y + *y += dy + box.Translate(0, dy) + } +} + +func prepJustifiedLine(lines *[]string, strbuf []string, strWidth, w float64, fontSize int, fontName string) { + bb := prepBytes(" ", fontName) + var sb strings.Builder + sb.WriteString("[") + wc := len(strbuf) + dx := font.GlyphSpaceUnits(float64((w-strWidth))/float64(wc-1), fontSize) + for i := 0; i < wc; i++ { + s := prepBytes(strbuf[i], fontName) + sb.WriteString(fmt.Sprintf(" (%s)", s)) + if i < wc-1 { + sb.WriteString(fmt.Sprintf(" %d (%s)", -int(dx), bb)) + } + } + sb.WriteString(" ] TJ") + *lines = append(*lines, sb.String()) +} + +func newPrepJustifiedString(fontName string, fontSize int) func(lines *[]string, s string, w float64, fontName string, fontSize *int, lastline, parIndent bool) int { + + // Not yet rendered content. + strbuf := []string{} + + // Width of strbuf's content in user space implied by fontSize. + var strWidth float64 + + // Indent first line of paragraphs. + var indent bool = true + + // Indentation string for first line of paragraphs. + identPrefix := " " + + blankWidth := font.TextWidth(" ", fontName, fontSize) + + return func(lines *[]string, s string, w float64, fontName string, fontSize *int, lastline, parIndent bool) int { + + if len(s) == 0 { + if len(strbuf) > 0 { + s1 := prepBytes(strings.Join(strbuf, " "), fontName) + s = fmt.Sprintf("(%s) Tj", s1) + *lines = append(*lines, s) + strbuf = []string{} + strWidth = 0 + } + if lastline { + return 0 + } + indent = true + if parIndent { + return 0 + } + return 1 + } + + linefeeds := 0 + ss := strings.Split(s, " ") + if parIndent && len(strbuf) == 0 && indent { + ss[0] = identPrefix + ss[0] + } + for _, s1 := range ss { + s1Width := font.TextWidth(s1, fontName, *fontSize) + bw := 0. + if len(strbuf) > 0 { + bw = blankWidth + } + if w-strWidth-(s1Width+bw) > 0 { + strWidth += s1Width + bw + strbuf = append(strbuf, s1) + continue + } + // Scale down font size. + fs := font.Size(s1, fontName, w) + if fs < *fontSize { + *fontSize = fs + } + if len(strbuf) == 0 { + prepJustifiedLine(lines, []string{s1}, s1Width, w, *fontSize, fontName) + } else { + // Note: Previous lines have whitespace based on bigger font size. + prepJustifiedLine(lines, strbuf, strWidth, w, *fontSize, fontName) + strbuf = []string{s1} + strWidth = s1Width + } + linefeeds++ + indent = false + } + return 0 + } +} + +// Prerender justified text in order to calculate bounding box height. +func preRenderJustifiedText(lines *[]string, r *Rectangle, scaleAbs, parIndent bool, + x, y, width, scale, mLeft, mRight, borderWidth float64, + fontName string, fontSize *int) float64 { + var ww float64 + if !scaleAbs { + ww = r.Width() * scale + } else { + if width > 0 { + ww = width * scale + } else { + box, _ := calcBoundingBoxForLines(*lines, x, y, fontName, *fontSize) + ww = box.Width() * scale + } + } + ww -= mLeft + mRight + 2*borderWidth + prepJustifiedString := newPrepJustifiedString(fontName, *fontSize) + l := []string{} + for i, s := range *lines { + linefeeds := prepJustifiedString(&l, s, ww, fontName, fontSize, false, parIndent) + for j := 0; j < linefeeds; j++ { + l = append(l, "") + } + isLastLine := i == len(*lines)-1 + if isLastLine { + prepJustifiedString(&l, "", ww, fontName, fontSize, true, parIndent) + } + } + *lines = l + return ww +} + +func scaleFontSize(r *Rectangle, lines []string, scaleAbs bool, + scale, width, x, y, mLeft, mRight, borderWidth float64, + fontName string, fontSize *int) { + if scaleAbs { + *fontSize = int(float64(*fontSize) * scale) + } else { + www := width + if width == 0 { + box, _ := calcBoundingBoxForLines(lines, x, y, fontName, *fontSize) + www = box.Width() + mLeft + mRight + 2*borderWidth + } + *fontSize = int(r.Width() * scale * float64(*fontSize) / www) + } +} + +func horizontalWrapUp(box *Rectangle, maxLine string, hAlign HAlignment, + x *float64, width, ww, mLeft, mRight, borderWidth float64, + fontName string, fontSize *int) { + switch hAlign { + case AlignLeft: + box.Translate(mLeft+borderWidth, 0) + *x += mLeft + borderWidth + case AlignJustify: + if width > 0 { + box.Translate(mLeft+borderWidth, 0) + *x += mLeft + borderWidth + } else { + box.Translate(-ww/2, 0) + *x -= ww / 2 + } + case AlignRight: + box.Translate(-box.Width()-mRight-borderWidth, 0) + *x -= mRight + borderWidth + case AlignCenter: + box.Translate(-box.Width()/2, 0) + } + + if hAlign == AlignJustify { + box.UR.X = box.LL.X + ww + mRight + borderWidth + box.LL.X -= mLeft + borderWidth + } else if width > 0 { + netWidth := width - 2*borderWidth - mLeft - mRight + if box.Width() > netWidth { + *fontSize = font.Size(maxLine, fontName, netWidth) + } + switch hAlign { + case AlignLeft: + box.UR.X = box.LL.X + width - mLeft - borderWidth + box.LL.X -= mLeft + borderWidth + case AlignRight: + box.LL.X = box.UR.X - width + box.Translate(mRight+borderWidth, 0) + case AlignCenter: + box.LL.X = box.UR.X - width + box.Translate(box.Width()/2-(box.UR.X-*x), 0) + } + } else { + box.LL.X -= mLeft + borderWidth + box.UR.X += mRight + borderWidth + } +} + +func createBoundingBoxForColumn(r *Rectangle, x, y *float64, + hAlign HAlignment, + vAlign VAlignment, + width float64, + minHeight float64, + dx, dy float64, + mTop, mBot, mLeft, mRight float64, + borderWidth float64, + scale float64, + scaleAbs bool, + parIndent bool, + fontName string, + fontSize *int, lines *[]string) *Rectangle { + + var ww float64 + if hAlign == AlignJustify { + ww = preRenderJustifiedText(lines, r, scaleAbs, parIndent, *x, *y, width, scale, mLeft, mRight, borderWidth, fontName, fontSize) + } + + if hAlign != AlignJustify { + scaleFontSize(r, *lines, scaleAbs, scale, width, *x, *y, mLeft, mRight, borderWidth, fontName, fontSize) + } + + // Apply vertical alignment. + var dy1 float64 + switch vAlign { + case AlignTop: + dy1 = deltaAlignTop(fontName, *fontSize, mTop+borderWidth) + case AlignMiddle: + dy1 = deltaAlignMiddle(fontName, *fontSize, len(*lines), mTop, mBot) + case AlignBottom: + dy1 = deltaAlignBottom(fontName, *fontSize, len(*lines), mBot) + } + *y += math.Ceil(dy1) + + box, maxLine := calcBoundingBoxForLines(*lines, *x, *y, fontName, *fontSize) + // maxLine for hAlign != AlignJustify only! + horizontalWrapUp(box, maxLine, hAlign, x, width, ww, mLeft, mRight, borderWidth, fontName, fontSize) + + box.LL.Y -= mBot + borderWidth + box.UR.Y += mTop + borderWidth + + if minHeight > 0 && box.Height() < minHeight { + box.LL.Y = box.UR.Y - minHeight + } + + horAdjustBoundingBoxForLines(r, box, dx, dy, x, y) + + return box +} + +func flushJustifiedStringToBuf(buf *bytes.Buffer, s string, x, y float64, strokeCol, fillCol SimpleColor, rm RenderMode) { + buf.WriteString(fmt.Sprintf("BT 0 Tw %.2f %.2f %.2f RG %.2f %.2f %.2f rg %.2f %.2f Td %d Tr %s ET ", + strokeCol.R, strokeCol.G, strokeCol.B, fillCol.R, fillCol.G, fillCol.B, x, y, rm, s)) +} + +func scaleXForRegion(x float64, mediaBox, region *Rectangle) float64 { + return x / mediaBox.Width() * region.Width() +} + +func scaleYForRegion(y float64, mediaBox, region *Rectangle) float64 { + return y / mediaBox.Width() * region.Width() +} + +func drawMargins(buf *bytes.Buffer, c SimpleColor, colBB *Rectangle, borderWidth, mLeft, mRight, mTop, mBot float64) { + SetLineWidth(buf, 0) + SetStrokeColor(buf, c) + + r := RectForWidthAndHeight(colBB.LL.X+borderWidth, colBB.LL.Y+borderWidth, colBB.Width()-2*borderWidth, mBot) + FillRect(buf, r, c) + + r = RectForWidthAndHeight(colBB.LL.X+borderWidth, colBB.Height()-borderWidth-mTop, colBB.Width()-2*borderWidth, mTop) + FillRect(buf, r, c) + + r = RectForWidthAndHeight(colBB.LL.X+borderWidth, colBB.LL.Y+borderWidth+mBot, mLeft, colBB.Height()-2*borderWidth-mTop-mBot) + FillRect(buf, r, c) + + r = RectForWidthAndHeight(colBB.UR.X-borderWidth-mRight, colBB.LL.Y+borderWidth+mBot, mRight, colBB.Height()-2*borderWidth-mTop-mBot) + FillRect(buf, r, c) +} + +func renderBackgroundAndBorder(buf *bytes.Buffer, td TextDescriptor, borderWidth float64, colBB *Rectangle) { + SetLineJoinStyle(buf, td.BorderStyle) + if td.ShowBackground { + SetLineWidth(buf, borderWidth) + c := td.BackgroundCol + if td.ShowBorder { + c = td.BorderCol + } + SetStrokeColor(buf, c) + r := RectForWidthAndHeight(colBB.LL.X+borderWidth/2, colBB.LL.Y+borderWidth/2, colBB.Width()-borderWidth, colBB.Height()-borderWidth) + FillRect(buf, r, td.BackgroundCol) + } else if td.ShowBorder { + SetLineWidth(buf, borderWidth) + SetStrokeColor(buf, td.BorderCol) + r := RectForWidthAndHeight(colBB.LL.X+borderWidth/2, colBB.LL.Y+borderWidth/2, colBB.Width()-borderWidth, colBB.Height()-borderWidth) + DrawRect(buf, r) + } +} + +func renderText(buf *bytes.Buffer, lines []string, td TextDescriptor, x, y float64, fontName string, fontSize int) { + lh := font.LineHeight(fontName, fontSize) + for _, s := range lines { + if td.HAlign != AlignJustify { + lineBB := calcBoundingBox(s, x, y, td.FontName, fontSize) + // Apply horizontal alignment. + var dx float64 + switch td.HAlign { + case AlignCenter: + dx = lineBB.Width() / 2 + case AlignRight: + dx = lineBB.Width() + } + lineBB.Translate(-dx, 0) + if td.ShowLineBB { + // Draw line bounding box. + SetStrokeColor(buf, Black) + DrawRect(buf, lineBB) + } + writeStringToBuf(buf, s, x-dx, y, td.StrokeCol, td.FillCol, td.RMode, fontName) + y -= lh + continue + } + + if len(s) > 0 { + flushJustifiedStringToBuf(buf, s, x, y, td.StrokeCol, td.FillCol, td.RMode) + } + y -= lh + } +} + +// WriteColumn writes a text column using s at position x/y using a certain font, fontsize and a desired horizontal and vertical alignment. +// Enforce a desired column width by supplying a width > 0 (especially useful for justified text). +// It returns the bounding box of this column. +func WriteColumn(buf *bytes.Buffer, mediaBox, region *Rectangle, td TextDescriptor, width float64) *Rectangle { + x, y, dx, dy := td.X, td.Y, td.Dx, td.Dy + mTop, mBot, mLeft, mRight := td.MTop, td.MBot, td.MLeft, td.MRight + s, fontSize, borderWidth := td.Text, td.FontSize, td.BorderWidth + + r := mediaBox + if region != nil { + r = region + dx = scaleXForRegion(dx, mediaBox, r) + dy = scaleYForRegion(dy, mediaBox, r) + width = scaleXForRegion(width, mediaBox, r) + fontSize = int(scaleYForRegion(float64(fontSize), mediaBox, r)) + mTop = scaleYForRegion(mTop, mediaBox, r) + mBot = scaleYForRegion(mBot, mediaBox, r) + mLeft = scaleXForRegion(mLeft, mediaBox, r) + mRight = scaleXForRegion(mRight, mediaBox, r) + borderWidth = scaleXForRegion(borderWidth, mediaBox, r) + } + + if x >= 0 { + x = r.LL.X + x + } + if y >= 0 { + y = r.LL.Y + y + } + + // Position text horizontally centered for x < 0. + if x < 0 { + x = r.LL.X + r.Width()/2 + } + + // Position text vertically centered for y < 0. + if y < 0 { + y = r.LL.Y + r.Height()/2 + } + + // Apply offset. + x += dx + y += dy + + // Cache haircross coordinates. + x0, y0 := x, y + + if font.IsCoreFont(td.FontName) && utf8.ValidString(s) { + s = decodeUTF8ToByte(s) + } + + s = strings.ReplaceAll(s, "\\n", "\n") + lines := []string{} + for _, l := range fieldsFunc(s, func(c rune) bool { return c == 0x0a }) { + lines = append(lines, l) + } + + if !td.ScaleAbs { + if td.Scale > 1 { + td.Scale = 1 + } + } + + colBB := createBoundingBoxForColumn(r, &x, &y, + td.HAlign, td.VAlign, width, td.MinHeight, + dx, dy, mTop, mBot, mLeft, mRight, borderWidth, + td.Scale, td.ScaleAbs, + td.ParIndent, td.FontName, &fontSize, &lines) + + setFont(buf, td.FontKey, float32(fontSize)) + m := calcRotateTransformMatrix(td.Rotation, x, y, colBB) + fmt.Fprintf(buf, "q %.2f %.2f %.2f %.2f %.2f %.2f cm ", m[0][0], m[0][1], m[1][0], m[1][1], m[2][0], m[2][1]) + + x -= colBB.LL.X + y -= colBB.LL.Y + colBB.Translate(-colBB.LL.X, -colBB.LL.Y) + + // Render background and border. + if td.ShowTextBB { + renderBackgroundAndBorder(buf, td, borderWidth, colBB) + } + + // Render margins. + if td.ShowMargins { + drawMargins(buf, LightGray, colBB, borderWidth, mLeft, mRight, mTop, mBot) + } + + // Render text. + renderText(buf, lines, td, x, y, td.FontName, fontSize) + + buf.WriteString("Q ") + + if td.HairCross { + DrawHairCross(buf, x0, y0, r) + } + + return colBB +} + +// WriteMultiLine writes s at position x/y using a certain font, fontsize and a desired horizontal and vertical alignment. +// It returns the bounding box of this text column. +func WriteMultiLine(buf *bytes.Buffer, mediaBox, region *Rectangle, td TextDescriptor) *Rectangle { + return WriteColumn(buf, mediaBox, region, td, 0) +} + +func anchorPosAndAlign(a anchor, r *Rectangle) (x, y float64, hAlign HAlignment, vAlign VAlignment) { + switch a { + case TopLeft: + x, y, hAlign, vAlign = 0, r.Height(), AlignLeft, AlignTop + case TopCenter: + x, y, hAlign, vAlign = -1, r.Height(), AlignCenter, AlignTop + case TopRight: + x, y, hAlign, vAlign = r.Width(), r.Height(), AlignRight, AlignTop + case Left: + x, y, hAlign, vAlign = 0, -1, AlignLeft, AlignMiddle + case Center: + x, y, hAlign, vAlign = -1, -1, AlignCenter, AlignMiddle + case Right: + x, y, hAlign, vAlign = r.Width(), -1, AlignRight, AlignMiddle + case BottomLeft: + x, y, hAlign, vAlign = 0, 0, AlignLeft, AlignBottom + case BottomCenter: + x, y, hAlign, vAlign = -1, 0, AlignCenter, AlignBottom + case BottomRight: + x, y, hAlign, vAlign = r.Width(), 0, AlignRight, AlignBottom + } + return +} + +// WriteMultiLineAnchored writes multiple lines with anchored position and returns its bounding box. +func WriteMultiLineAnchored(buf *bytes.Buffer, mediaBox, region *Rectangle, td TextDescriptor, a anchor) *Rectangle { + r := mediaBox + if region != nil { + r = region + } + td.X, td.Y, td.HAlign, td.VAlign = anchorPosAndAlign(a, r) + return WriteMultiLine(buf, mediaBox, region, td) +} + +// WriteColumnAnchored writes a justified text column with anchored position and returns its bounding box. +func WriteColumnAnchored(buf *bytes.Buffer, mediaBox, region *Rectangle, td TextDescriptor, a anchor, width float64) *Rectangle { + r := mediaBox + if region != nil { + r = region + } + td.HAlign = AlignJustify + td.X, td.Y, _, td.VAlign = anchorPosAndAlign(a, r) + return WriteColumn(buf, mediaBox, region, td, width) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/createAnnotations.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/createAnnotations.go new file mode 100644 index 0000000..68b9c25 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/createAnnotations.go @@ -0,0 +1,1204 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "path" + "path/filepath" + "time" +) + +// Functions needed to create a test.pdf that gets used for validation testing (see process_test.go) + +func createTextAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + d := Dict(map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Text"), + "Contents": StringLiteral("Text Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 5), + "C": NewNumberArray(1, 0, 0), + "Name": Name("Note"), + }) + + return xRefTable.IndRefForNewObject(d) +} + +func createLinkAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + usageDict := Dict( + map[string]Object{ + "CreatorInfo": Dict( + map[string]Object{ + "Creator": StringLiteral("pdfcpu"), + "Subtype": Name("Technical"), + }, + ), + "Language": Dict( + map[string]Object{ + "Lang": StringLiteral("en-us"), + "Preferred": Name("ON"), + }, + ), + "Export": Dict( + map[string]Object{ + "ExportState": Name("ON"), + }, + ), + "Zoom": Dict( + map[string]Object{ + "min": Float(0), + }, + ), + "Print": Dict( + map[string]Object{ + "Subtype": Name("Watermark"), + "PrintState": Name("ON"), + }, + ), + "View": Dict( + map[string]Object{ + "ViewState": Name("Ind"), + }, + ), + "User": Dict( + map[string]Object{ + "Type": Name("ON"), + "Name": StringLiteral("Horst Rutter"), + }, + ), + "PageElement": Dict( + map[string]Object{ + "Subtype": Name("FG"), + }, + ), + }, + ) + + optionalContentGroupDict := Dict( + map[string]Object{ + "Type": Name("OCG"), + "Name": StringLiteral("OCG"), + "Intent": Name("Design"), + "Usage": usageDict, + }, + ) + + uriActionDict := Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("URI"), + "URI": StringLiteral("https://golang.org"), + }, + ) + + indRef, err := xRefTable.IndRefForNewObject(uriActionDict) + if err != nil { + return nil, err + } + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Link"), + "Contents": StringLiteral("Link Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 5), + "C": NewNumberArray(0, 0, 1), + "A": *indRef, + "H": Name("I"), + "PA": *indRef, + "OC": optionalContentGroupDict, + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createFreeTextAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("FreeText"), + "Contents": StringLiteral("FreeText Annotation"), + "F": Integer(128), // Lock + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, 1, 0), + "DA": StringLiteral("DA"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createLineAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Line"), + "Contents": StringLiteral("Line Annotation"), + "F": Integer(128), // Lock + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, 1, 0), + "L": annotRect, + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createSquareAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Square"), + "Contents": StringLiteral("Square Annotation"), + "F": Integer(128), // Lock + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, .3, .3), + "IC": NewNumberArray(0.8, .8, .8), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createCircleAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Circle"), + "Contents": StringLiteral("Circle Annotation"), + "F": Integer(128), // Lock + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 10), + "C": NewNumberArray(0.5, 0, 5, 0), + "IC": NewNumberArray(0.8, .8, .8), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createPolygonAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + // Construct a polyline using the annot rects both lower corners and the upper right corner. + v := Array{nil, nil, nil, nil} + copy(v, annotRect) + v = append(v, annotRect[2]) + v = append(v, annotRect[1]) + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Polygon"), + "Contents": StringLiteral("Polygon Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, 1, 0), + "Vertices": v, + "IC": NewNumberArray(0.3, 0.5, 0.0), + "BS": Dict( + map[string]Object{ + "Type": Name("Border"), + "W": Float(0.5), + "S": Name("D"), + }, + ), + "BE": Dict( + map[string]Object{ + "S": Name("C"), + "I": Float(1), + }, + ), + "IT": Name("PolygonCloud"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createPolyLineAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + // Construct a polyline using the annot rects both lower corners and the upper right corner. + v := Array{nil, nil, nil, nil} + copy(v, annotRect) + v = append(v, annotRect[2]) + v = append(v, annotRect[1]) + + optionalContentGroupDict := Dict( + map[string]Object{ + "Type": Name("OCG"), + "Name": StringLiteral("OCG"), + "Intent": NewNameArray("Design", "View"), + }, + ) + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("PolyLine"), + "Contents": StringLiteral("PolyLine Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, 1, 0), + "Vertices": v, + "OC": optionalContentGroupDict, + "IC": NewNumberArray(0.3, 0.5, 0.0), + "BS": Dict( + map[string]Object{ + "Type": Name("Border"), + "W": Float(0.5), + "S": Name("D"), + }, + ), + "IT": Name("PolygonCloud"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createHighlightAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + // Create a quad points array corresponding to the annot rect. + ar := annotRect + + qp := Array{} + qp = append(qp, ar[0]) + qp = append(qp, ar[1]) + qp = append(qp, ar[2]) + qp = append(qp, ar[1]) + qp = append(qp, ar[2]) + qp = append(qp, ar[3]) + qp = append(qp, ar[0]) + qp = append(qp, ar[3]) + + optionalContentGroupDict := Dict( + map[string]Object{ + "Type": Name("OCG"), + "Name": StringLiteral("OCG"), + }, + ) + + optionalContentMembershipDict := Dict( + map[string]Object{ + "Type": Name("OCMD"), + "OCGs": Array{nil, optionalContentGroupDict}, + "P": Name("AllOn"), + "VE": Array{}, + }, + ) + + _ = optionalContentMembershipDict + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Highlight"), + "Contents": StringLiteral("Highlight Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(.2, 0, 0), + "OC": optionalContentMembershipDict, + "QuadPoints": qp, + "T": StringLiteral("MyTitle"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createUnderlineAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + // Create a quad points array corresponding to annot rect. + ar := annotRect + + qp := Array{} + qp = append(qp, ar[0]) + qp = append(qp, ar[1]) + qp = append(qp, ar[2]) + qp = append(qp, ar[1]) + qp = append(qp, ar[2]) + qp = append(qp, ar[3]) + qp = append(qp, ar[0]) + qp = append(qp, ar[3]) + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Underline"), + "Contents": StringLiteral("Underline Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(.5, 0, 0), + "QuadPoints": qp, + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createSquigglyAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + // Create a quad points array corresponding to annot rect. + ar := annotRect + + qp := Array{} + qp = append(qp, ar[0]) + qp = append(qp, ar[1]) + qp = append(qp, ar[2]) + qp = append(qp, ar[1]) + qp = append(qp, ar[2]) + qp = append(qp, ar[3]) + qp = append(qp, ar[0]) + qp = append(qp, ar[3]) + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Squiggly"), + "Contents": StringLiteral("Squiggly Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(.5, 0, 0), + "QuadPoints": qp, + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createStrikeOutAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + // Create a quad points array corresponding to annot rect. + ar := annotRect + + qp := Array{} + qp = append(qp, ar[0]) + qp = append(qp, ar[1]) + qp = append(qp, ar[2]) + qp = append(qp, ar[1]) + qp = append(qp, ar[2]) + qp = append(qp, ar[3]) + qp = append(qp, ar[0]) + qp = append(qp, ar[3]) + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("StrikeOut"), + "Contents": StringLiteral("StrikeOut Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(.5, 0, 0), + "QuadPoints": qp, + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createCaretAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Caret"), + "Contents": StringLiteral("Caret Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0.5, 0.5, 0), + "RD": NewNumberArray(0, 0, 0, 0), + "Sy": Name("None"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createStampAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Stamp"), + "Contents": StringLiteral("Stamp Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0.5, 0.5, 0.9), + "Name": Name("Approved"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createInkAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + ar := annotRect + + l := Array{ + Array{ar[0], ar[1], ar[2], ar[1]}, + Array{ar[2], ar[1], ar[2], ar[3]}, + Array{ar[2], ar[3], ar[0], ar[3]}, + Array{ar[0], ar[3], ar[0], ar[1]}, + } + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Ink"), + "Contents": StringLiteral("Ink Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0.5, 0, 0.3), + "InkList": l, + "ExData": Dict( + map[string]Object{ + "Type": Name("ExData"), + "Subtype": Name("Markup3D"), + }, + ), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createPopupAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Popup"), + "Contents": StringLiteral("Ink Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0.5, 0, 0.3), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createFileAttachmentAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + // macOS starts up iTunes for FileAttachments. + + fileName := testAudioFileWAV + + ir, err := xRefTable.NewEmbeddedFileStreamDict(fileName) + if err != nil { + return nil, err + } + + fn := path.Base(fileName) + fileSpecDict, err := xRefTable.NewFileSpecDict(fn, encodeUTF16String(fn), "attached by pdfcpu", *ir) + if err != nil { + return nil, err + } + + ir, err = xRefTable.IndRefForNewObject(fileSpecDict) + if err != nil { + return nil, err + } + + now := StringLiteral(DateString(time.Now())) + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("FileAttachment"), + "Contents": StringLiteral("FileAttachment Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "M": now, + "F": Integer(0), + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0.5, 0.0, 0.5), + "CA": Float(0.95), + "CreationDate": now, + "Name": Name("Paperclip"), + "FS": *ir, + "NM": StringLiteral("SoundFileAttachmentAnnot"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createFileSpecDict(xRefTable *XRefTable, fileName string) (Dict, error) { + ir, err := xRefTable.NewEmbeddedFileStreamDict(fileName) + if err != nil { + return nil, err + } + fn := path.Base(fileName) + return xRefTable.NewFileSpecDict(fn, encodeUTF16String(fn), "attached by pdfcpu", *ir) +} + +func createSoundObject(xRefTable *XRefTable) (*IndirectRef, error) { + fileName := testAudioFileWAV + fileSpecDict, err := createFileSpecDict(xRefTable, fileName) + if err != nil { + return nil, err + } + return xRefTable.NewSoundStreamDict(fileName, 44100, fileSpecDict) +} + +func createSoundAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + indRef, err := createSoundObject(xRefTable) + if err != nil { + return nil, err + } + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Sound"), + "Contents": StringLiteral("Sound Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, 0.5, 0.5), + "Sound": *indRef, + "Name": Name("Speaker"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createMovieDict(xRefTable *XRefTable) (*IndirectRef, error) { + + // not supported: mp3,mp4,m4a + + fileSpecDict, err := createFileSpecDict(xRefTable, testAudioFileWAV) + if err != nil { + return nil, err + } + + d := Dict( + map[string]Object{ + "F": fileSpecDict, + "Aspect": NewIntegerArray(200, 200), + "Rotate": Integer(0), + "Poster": Boolean(true), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createMovieAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + indRef, err := createMovieDict(xRefTable) + if err != nil { + return nil, err + } + + movieActivationDict := Dict( + map[string]Object{ + "Start": Integer(10), + "Duration": Integer(60), + "Rate": Float(1.0), + "Volume": Float(1.0), + "ShowControls": Boolean(true), + "Mode": Name("Once"), + "Synchronous": Boolean(false), + }, + ) + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Movie"), + "Contents": StringLiteral("Movie Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 3), // rounded corners don't work + "C": NewNumberArray(0.3, 0.5, 0.5), + "Movie": *indRef, + "T": StringLiteral("Sample Movie"), + "A": movieActivationDict, + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createMediaRenditionAction(xRefTable *XRefTable, mediaClipDataDict *IndirectRef) Dict { + + r := createMediaRendition(xRefTable, mediaClipDataDict) + + return Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("Rendition"), + "R": *r, // rendition object + "OP": Integer(0), // Play + }, + ) +} + +func createSelectorRenditionAction(mediaClipDataDict *IndirectRef) Dict { + + r := createSelectorRendition(mediaClipDataDict) + + return Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("Rendition"), + "R": *r, // rendition object + "OP": Integer(0), // Play + }, + ) +} + +func createScreenAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + ir, err := createMediaClipDataDict(xRefTable) + if err != nil { + return nil, err + } + + mediaRenditionAction := createMediaRenditionAction(xRefTable, ir) + + selectorRenditionAction := createSelectorRenditionAction(ir) + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Screen"), + "Contents": StringLiteral("Screen Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 3), + "C": NewNumberArray(0.2, 0.8, 0.5), + "A": mediaRenditionAction, + "AA": Dict( + map[string]Object{ + "D": selectorRenditionAction, + }, + ), + }, + ) + + ir, err = xRefTable.IndRefForNewObject(d) + if err != nil { + return nil, err + } + + // Inject indRef of screen annotation into action dicts. + mediaRenditionAction.Insert("AN", *ir) + selectorRenditionAction.Insert("AN", *ir) + + return ir, nil +} + +func createWidgetAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + appearanceCharacteristicsDict := Dict( + map[string]Object{ + "R": Integer(0), + "BC": NewNumberArray(0.0, 0.0, 0.0), + "BG": NewNumberArray(0.5, 0.0, 0.5), + "RC": StringLiteral("Rollover caption"), + "IF": Dict( + map[string]Object{ + "SW": Name("A"), + "S": Name("A"), + "FB": Boolean(true), + }, + ), + }, + ) + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Widget"), + "Contents": StringLiteral("Widget Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 3), + "C": NewNumberArray(0.5, 0.5, 0.5), + "MK": appearanceCharacteristicsDict, + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createXObjectForPrinterMark(xRefTable *XRefTable) (*IndirectRef, error) { + buf := `0 0 m 0 25 l 25 25 l 25 0 l s` + sd, _ := xRefTable.NewStreamDictForBuf([]byte(buf)) + sd.InsertName("Type", "XObject") + sd.InsertName("Subtype", "Form") + sd.InsertInt("FormType", 1) + sd.Insert("BBox", NewNumberArray(0, 0, 25, 25)) + sd.Insert("Matrix", NewIntegerArray(1, 0, 0, 1, 0, 0)) + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func createPrinterMarkAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + ir, err := createXObjectForPrinterMark(xRefTable) + if err != nil { + return nil, err + } + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("PrinterMark"), + "Contents": StringLiteral("PrinterMark Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 3), + "C": NewNumberArray(0.2, 0.8, 0.5), + "F": Integer(0), + "AP": Dict( + map[string]Object{ + "N": *ir, + }, + ), + "MN": Name("ColorBar"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createXObjectForWaterMark(xRefTable *XRefTable) (*IndirectRef, error) { + fIndRef, err := createFontDict(xRefTable, "Helvetica") + if err != nil { + return nil, err + } + + fResDict := NewDict() + fResDict.Insert("F1", *fIndRef) + resourceDict := NewDict() + resourceDict.Insert("Font", fResDict) + + buf := `0 0 m 0 200 l 200 200 l 200 0 l s BT /F1 48 Tf 0.7 0.7 -0.7 0.7 30 10 Tm 1 Tr 2 w (Watermark) Tj ET` + sd, _ := xRefTable.NewStreamDictForBuf([]byte(buf)) + sd.InsertName("Type", "XObject") + sd.InsertName("Subtype", "Form") + sd.InsertInt("FormType", 1) + sd.Insert("BBox", NewNumberArray(0, 0, 200, 200)) + sd.Insert("Matrix", NewIntegerArray(1, 0, 0, 1, 0, 0)) + sd.Insert("Resources", resourceDict) + + if err = sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func createWaterMarkAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + ir, err := createXObjectForWaterMark(xRefTable) + if err != nil { + return nil, err + } + + d1 := Dict( + map[string]Object{ + "Type": Name("FixedPrint"), + "Matrix": NewIntegerArray(1, 0, 0, 1, 72, -72), + "H": Float(0), + "V": Float(0), + }, + ) + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Watermark"), + "Contents": StringLiteral("Watermark Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 3), + "C": NewNumberArray(0.2, 0.8, 0.5), + "F": Integer(0), + "AP": Dict( + map[string]Object{ + "N": *ir, + }, + ), + "FixedPrint": d1, + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func create3DAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("3D"), + "Contents": StringLiteral("3D Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 3), + "C": NewNumberArray(0.2, 0.8, 0.5), + "F": Integer(0), + "3DD": NewDict(), // stream or 3D reference dict + "3DV": Name("F"), + "3DA": NewDict(), // activation dict + "3DI": Boolean(true), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createRedactAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + // Create a quad points array corresponding to annot rect. + qp := Array{} + qp = append(qp, annotRect[0]) + qp = append(qp, annotRect[1]) + qp = append(qp, annotRect[2]) + qp = append(qp, annotRect[1]) + qp = append(qp, annotRect[2]) + qp = append(qp, annotRect[3]) + qp = append(qp, annotRect[0]) + qp = append(qp, annotRect[3]) + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Redact"), + "Contents": StringLiteral("Redact Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 3), + "C": NewNumberArray(0.2, 0.8, 0.5), + "F": Integer(0), + "QuadPoints": qp, + "IC": NewNumberArray(0.5, 0.0, 0.9), + "OverlayText": StringLiteral("An overlay"), + "Repeat": Boolean(true), + "DA": StringLiteral("x"), + "Q": Integer(1), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createRemoteGoToAction(xRefTable *XRefTable) (*IndirectRef, error) { + + d := Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("GoToR"), + "F": StringLiteral(".\\/go.pdf"), + "D": Array{Integer(0), Name("Fit")}, + "NewWindow": Boolean(true), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createLinkAnnotationWithRemoteGoToAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + ir, err := createRemoteGoToAction(xRefTable) + if err != nil { + return nil, err + } + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Link"), + "Contents": StringLiteral("Link Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, 0, 1), + "A": *ir, + "H": Name("I"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createEmbeddedGoToAction(xRefTable *XRefTable) (*IndirectRef, error) { + + f := filepath.Join(testDir, "go.pdf") + fileSpecDict, err := createFileSpecDict(xRefTable, f) + if err != nil { + return nil, err + } + + d := Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("GoToE"), + "F": fileSpecDict, + "D": Array{Integer(0), Name("Fit")}, + "NewWindow": Boolean(true), // not honored by Acrobat Reader. + "T": Dict( + map[string]Object{ + "R": Name("C"), + "N": StringLiteral(f), + }, + ), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createLinkAnnotationWithEmbeddedGoToAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + ir, err := createEmbeddedGoToAction(xRefTable) + if err != nil { + return nil, err + } + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Link"), + "Contents": StringLiteral("Link Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, 0, 1), + "A": *ir, + "H": Name("I"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createLinkAnnotationDictWithLaunchAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Link"), + "Contents": StringLiteral("Link Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, 0, 1), + "A": Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("Launch"), + "F": StringLiteral(".\\/golang.pdf"), // e.g pdf, wav.. + "Win": Dict( + map[string]Object{ + "F": StringLiteral("golang.pdf"), + "O": StringLiteral("O"), + }, + ), + "NewWindow": Boolean(true), + }, + ), + "H": Name("I"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createLinkAnnotationDictWithThreadAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Link"), + "Contents": StringLiteral("Link Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, 0, 1), + "A": Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("Thread"), + "D": Integer(0), // jump to first article thread + "B": Integer(0), // jump to first bead + }, + ), + "H": Name("I"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createLinkAnnotationDictWithSoundAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + ir, err := createSoundObject(xRefTable) + if err != nil { + return nil, err + } + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Link"), + "Contents": StringLiteral("Link Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, 0, 1), + "A": Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("Sound"), + "Sound": *ir, + "Synchronous": Boolean(false), + "Repeat": Boolean(false), + "Mix": Boolean(false), + }, + ), + "H": Name("I"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createLinkAnnotationDictWithMovieAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Link"), + "Contents": StringLiteral("Link Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, 0, 1), + "A": Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("Movie"), + "T": StringLiteral("Sample Movie"), + "Operation": Name("Play"), + }, + ), + "H": Name("I"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createLinkAnnotationDictWithHideAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + hideActionDict := Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("Hide"), + "H": Boolean(true), + }, + ) + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("Link"), + "Contents": StringLiteral("Link Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 1), + "C": NewNumberArray(0, 0, 1), + "A": hideActionDict, + "H": Name("I"), + }, + ) + + ir, err := xRefTable.IndRefForNewObject(d) + if err != nil { + return nil, err + } + + // We hide the link annotation itself. + hideActionDict.Insert("T", *ir) + + return ir, nil +} + +func createTrapNetAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) { + + ir, err := createFontDict(xRefTable, "Helvetica") + if err != nil { + return nil, err + } + + d := Dict( + map[string]Object{ + "Type": Name("Annot"), + "Subtype": Name("TrapNet"), + "Contents": StringLiteral("TrapNet Annotation"), + "Rect": annotRect, + "P": pageIndRef, + "Border": NewIntegerArray(0, 0, 3), + "C": NewNumberArray(0.2, 0.8, 0.5), + "F": Integer(0), + "LastModified": StringLiteral(DateString(time.Now())), + "FontFauxing": Array{*ir}, + }, + ) + + return xRefTable.IndRefForNewObject(d) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/createRenditions.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/createRenditions.go new file mode 100644 index 0000000..ca8ad86 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/createRenditions.go @@ -0,0 +1,335 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +// Functions needed to create a test.pdf that gets used for validation testing (see process_test.go) + +func createMHBEDict() *Dict { + + softwareIdentDict := Dict( + map[string]Object{ + "Type": Name("SoftwareIdentifier"), + "U": StringLiteral("vnd.adobe.swname:ADBE_Acrobat"), + "L": NewIntegerArray(0), + "H": NewIntegerArray(), + "OS": NewStringArray(), + }, + ) + + mediaCriteriaDict := Dict( + map[string]Object{ + "Type": Name("MediaCriteria"), + "A": Boolean(false), + "C": Boolean(false), + "O": Boolean(false), + "S": Boolean(false), + "R": Integer(0), + "D": Dict( + map[string]Object{ + "Type": Name("MinBitDepth"), + "V": Integer(0), + "M": Integer(0), + }, + ), + "V": Array{softwareIdentDict}, + "Z": Dict( + map[string]Object{ + "Type": Name("MinScreenSize"), + "V": NewIntegerArray(640, 480), + "M": Integer(0), + }, + ), + "P": NewNameArray("1.3"), + "L": NewStringArray("en-US"), + }, + ) + + mhbe := NewDict() + mhbe.Insert("C", mediaCriteriaDict) + + return &mhbe +} + +func createMediaPlayersDict() *Dict { + + softwareIdentDict := Dict( + map[string]Object{ + "Type": Name("SoftwareIdentifier"), + "U": StringLiteral("vnd.adobe.swname:ADBE_Acrobat"), + "L": NewIntegerArray(0), + "H": NewIntegerArray(), + "OS": NewStringArray(), + }, + ) + + mediaPlayerInfoDict := Dict( + map[string]Object{ + "Type": Name("MediaPlayerInfo"), + "PID": softwareIdentDict, + }, + ) + + d := Dict( + map[string]Object{ + "Type": Name("MediaPlayers"), + "MU": Array{mediaPlayerInfoDict}, + }, + ) + + return &d +} + +func createMediaOffsetDict() *Dict { + + timeSpanDict := Dict( + map[string]Object{ + "Type": Name("Timespan"), + "S": Name("S"), + "V": Integer(1), + }, + ) + + d := Dict( + map[string]Object{ + "Type": Name("MediaOffset"), + "S": Name("T"), + "T": timeSpanDict, + }, + ) + + return &d +} + +func createSectionMHBEDict() *Dict { + + d := createMediaOffsetDict() + + d1 := Dict( + map[string]Object{ + "B": *d, + "E": *d, + }, + ) + + return &d1 +} + +func createMediaClipDataDict(xRefTable *XRefTable) (*IndirectRef, error) { + + // not supported: mp3,mp4,m4a + + fileSpecDict, err := createFileSpecDict(xRefTable, testAudioFileWAV) + if err != nil { + return nil, err + } + + mediaPermissionsDict := Dict( + map[string]Object{ + "Type": Name("MediaPermissions"), + "TF": StringLiteral("TEMPNEVER"), //TEMPALWAYS + }, + ) + + mediaPlayersDict := createMediaPlayersDict() + + mhbe := Dict(map[string]Object{"BU": nil}) + + d := Dict( + map[string]Object{ + "Type": Name("MediaClip"), + "S": Name("MCD"), // media clip data + "N": StringLiteral("Sample Audio"), + "D": fileSpecDict, + "CT": StringLiteral("audio/x-wav"), + //"CT": StringLiteral("audio/mp4"), + //"CT": StringLiteral("video/mp4"), + "P": mediaPermissionsDict, + "Alt": NewStringArray("en-US", "My vacation", "de", "Mein Urlaub", "", "My vacation"), + "PL": *mediaPlayersDict, + "MH": mhbe, + "BE": mhbe, + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func createMediaPlayParamsMHBE() *Dict { + + timeSpanDict := Dict( + map[string]Object{ + "Type": Name("Timespan"), + "S": Name("S"), + "V": Float(10.0), + }, + ) + + mediaDurationDict := Dict( + map[string]Object{ + "Type": Name("MediaDuration"), + "S": Name("T"), + "T": timeSpanDict, + }, + ) + + d := Dict( + map[string]Object{ + "V": Integer(100), + "C": Boolean(false), + "F": Integer(5), + "D": mediaDurationDict, + "A": Boolean(true), + "RC": Float(1.0), + }, + ) + + return &d +} + +func createMediaPlayParamsDict() *Dict { + + d := createMediaPlayersDict() + mhbe := createMediaPlayParamsMHBE() + + d1 := Dict( + map[string]Object{ + "Type": Name("MediaPlayParams"), + "PL": *d, + "MH": *mhbe, + "BE": *mhbe, + }, + ) + + return &d1 +} + +func createFloatingWindowsParamsDict() *Dict { + + d := Dict( + map[string]Object{ + "Type": Name("FWParams"), + "D": NewIntegerArray(200, 200), + "RT": Integer(0), + "P": Integer(4), + "O": Integer(1), + "T": Boolean(true), + "UC": Boolean(true), + "R": Integer(0), + "TT": NewStringArray("en-US", "Special title", "de", "Spezieller Titel", "default title"), + }, + ) + + return &d +} + +func createScreenParamsDict() *Dict { + + d := createFloatingWindowsParamsDict() + + mhbe := Dict( + map[string]Object{ + "Type": Name("MediaScreenParams"), + "W": Integer(0), + "B": NewNumberArray(1.0, 0.0, 0.0), + "O": Float(1.0), + "M": Integer(0), + "F": *d, + }, + ) + + d1 := Dict( + map[string]Object{ + "Type": Name("MediaScreenParams"), + "MH": mhbe, + "BE": mhbe, + }, + ) + + return &d1 +} + +func createMediaRendition(xRefTable *XRefTable, mediaClipDataDict *IndirectRef) *Dict { + + mhbe := createMHBEDict() + + d1 := createMediaPlayParamsDict() + d2 := createScreenParamsDict() + + d3 := Dict( + map[string]Object{ + "Type": Name("Rendition"), + "S": Name("MR"), + "MH": *mhbe, + "BE": *mhbe, + "C": *mediaClipDataDict, + "P": *d1, + "SP": *d2, + }, + ) + + return &d3 +} + +func createSectionMediaRendition(mediaClipDataDict *IndirectRef) *Dict { + + mhbe := createSectionMHBEDict() + + mediaClipSectionDict := Dict( + map[string]Object{ + "Type": Name("MediaClip"), + "S": Name("MCS"), // media clip section + "N": StringLiteral("Sample movie"), + "D": *mediaClipDataDict, + "Alt": NewStringArray("en-US", "My vacation", "de", "Mein Urlaub", "", "default vacation"), + "MH": *mhbe, + "BE": *mhbe, + }, + ) + + mhbe = createMHBEDict() + + d := Dict( + map[string]Object{ + "Type": Name("Rendition"), + "S": Name("MR"), + "MH": *mhbe, + "BE": *mhbe, + "C": mediaClipSectionDict, + }, + ) + + return &d +} + +func createSelectorRendition(mediaClipDataDict *IndirectRef) *Dict { + + mhbe := createMHBEDict() + + r := createSectionMediaRendition(mediaClipDataDict) + + d := Dict( + map[string]Object{ + "Type": Name("Rendition"), + "S": Name("SR"), + "MH": *mhbe, + "BE": *mhbe, + "R": Array{*r}, + }, + ) + + return &d +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/createTestPDF.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/createTestPDF.go new file mode 100644 index 0000000..b9f8b98 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/createTestPDF.go @@ -0,0 +1,2006 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +// Functions needed to create a test.pdf that gets used for validation testing (see process_test.go) + +import ( + "bytes" + "fmt" + "path/filepath" +) + +var ( + testDir = "../../testdata" + testAudioFileWAV = filepath.Join(testDir, "resources", "test.wav") +) + +func createXRefTableWithRootDict() (*XRefTable, error) { + xRefTable := &XRefTable{ + Table: map[int]*XRefTableEntry{}, + Names: map[string]*Node{}, + Stats: NewPDFStats(), + } + + xRefTable.Table[0] = NewFreeHeadXRefTableEntry() + + one := 1 + xRefTable.Size = &one + + v := (V17) + xRefTable.HeaderVersion = &v + + xRefTable.PageCount = 0 + + // Optional infoDict. + xRefTable.Info = nil + + // Additional streams not implemented. + xRefTable.AdditionalStreams = nil + + rootDict := NewDict() + rootDict.InsertName("Type", "Catalog") + + ir, err := xRefTable.IndRefForNewObject(rootDict) + if err != nil { + return nil, err + } + + xRefTable.Root = ir + + return xRefTable, nil +} + +// CreateDemoXRef creates a minimal single page PDF file for demo purposes. +func CreateDemoXRef(p Page) (*XRefTable, error) { + xRefTable, err := createXRefTableWithRootDict() + if err != nil { + return nil, err + } + + rootDict, err := xRefTable.Catalog() + if err != nil { + return nil, err + } + + if err = addPageTreeWithSamplePage(xRefTable, rootDict, p); err != nil { + return nil, err + } + + return xRefTable, nil +} + +func addPageTreeForResourceDictInheritanceDemo(xRefTable *XRefTable, rootDict Dict) error { + + // Create root page node. + + fIndRef, err := createFontDict(xRefTable, "Courier") + if err != nil { + return err + } + + rootPagesDict := Dict( + map[string]Object{ + "Type": Name("Pages"), + "Count": Integer(1), + "MediaBox": RectForFormat("A4").Array(), + "Resources": Dict( + map[string]Object{ + "Font": Dict( + map[string]Object{ + "F99": *fIndRef, + }, + ), + }, + ), + }, + ) + + rootPageIndRef, err := xRefTable.IndRefForNewObject(rootPagesDict) + if err != nil { + return err + } + + // Create intermediate page node. + + f100IndRef, err := createFontDict(xRefTable, "Courier-Bold") + if err != nil { + return err + } + + pagesDict := Dict( + map[string]Object{ + "Type": Name("Pages"), + "Count": Integer(1), + "MediaBox": RectForFormat("A4").Array(), + "Resources": Dict( + map[string]Object{ + "Font": Dict( + map[string]Object{ + "F100": *f100IndRef, + }, + ), + }, + ), + }, + ) + + pagesIndRef, err := xRefTable.IndRefForNewObject(pagesDict) + if err != nil { + return err + } + + // Create leaf page node. + + p := Page{MediaBox: RectForFormat("A4"), Fm: FontMap{}, Buf: new(bytes.Buffer)} + + fontName := "Times-Roman" + k := p.Fm.EnsureKey(fontName) + td := TextDescriptor{ + Text: "This font is Times-Roman and it is defined in the resource dict of this page dict.", + FontName: fontName, + FontKey: k, + FontSize: 12, + Scale: 1., + ScaleAbs: true, + X: 300, + Y: 400, + } + + WriteMultiLine(p.Buf, p.MediaBox, nil, td) + + fontName = "Courier" + td = TextDescriptor{ + Text: "This font is Courier and it is inherited from the page root.", + FontName: fontName, + FontKey: "F99", + FontSize: 12, + Scale: 1., + ScaleAbs: true, + X: 300, + Y: 300, + } + + WriteMultiLine(p.Buf, p.MediaBox, nil, td) + + fontName = "Courier-Bold" + td = TextDescriptor{ + Text: "This font is Courier-Bold and it is inherited from an intermediate page node.", + FontName: fontName, + FontKey: "F100", + FontSize: 12, + Scale: 1., + ScaleAbs: true, + X: 300, + Y: 350, + } + + WriteMultiLine(p.Buf, p.MediaBox, nil, td) + + pageIndRef, err := createDemoPage(xRefTable, *pagesIndRef, p) + if err != nil { + return err + } + + pagesDict.Insert("Kids", Array{*pageIndRef}) + pagesDict.Insert("Parent", *rootPageIndRef) + + rootPagesDict.Insert("Kids", Array{*pagesIndRef}) + rootDict.Insert("Pages", *rootPageIndRef) + + return nil +} + +// CreateResourceDictInheritanceDemoXRef creates a page tree for testing resource dict inheritance. +func CreateResourceDictInheritanceDemoXRef() (*XRefTable, error) { + xRefTable, err := createXRefTableWithRootDict() + if err != nil { + return nil, err + } + + rootDict, err := xRefTable.Catalog() + if err != nil { + return nil, err + } + + if err = addPageTreeForResourceDictInheritanceDemo(xRefTable, rootDict); err != nil { + return nil, err + } + + return xRefTable, nil +} + +func createFunctionalShadingDict(xRefTable *XRefTable) Dict { + f := Dict( + map[string]Object{ + "FunctionType": Integer(2), + "Domain": NewNumberArray(1.0, 1.2, 1.4, 1.6, 1.8, 2.0), + "N": Float(1), + }, + ) + + d := Dict( + map[string]Object{ + "ShadingType": Integer(1), + "Function": Array{f}, + }, + ) + + return d +} + +func createRadialShadingDict(xRefTable *XRefTable) Dict { + f := Dict( + map[string]Object{ + "FunctionType": Integer(2), + "Domain": NewNumberArray(1.0, 1.2, 1.4, 1.6, 1.8, 2.0), + "N": Float(1), + }, + ) + + d := Dict( + map[string]Object{ + "ShadingType": Integer(3), + "Coords": NewNumberArray(0, 0, 50, 10, 10, 100), + "Function": Array{f}, + }, + ) + + return d +} + +func createStreamObjForHalftoneDictType6(xRefTable *XRefTable) (*IndirectRef, error) { + sd := &StreamDict{ + Dict: Dict( + map[string]Object{ + "Type": Name("Halftone"), + "HalftoneType": Integer(6), + "Width": Integer(100), + "Height": Integer(100), + "TransferFunction": Name("Identity"), + }, + ), + Content: []byte{}, + } + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func createStreamObjForHalftoneDictType10(xRefTable *XRefTable) (*IndirectRef, error) { + sd := &StreamDict{ + Dict: Dict( + map[string]Object{ + "Type": Name("Halftone"), + "HalftoneType": Integer(10), + "Xsquare": Integer(100), + "Ysquare": Integer(100), + }, + ), + Content: []byte{}, + } + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func createStreamObjForHalftoneDictType16(xRefTable *XRefTable) (*IndirectRef, error) { + sd := &StreamDict{ + Dict: Dict( + map[string]Object{ + "Type": Name("Halftone"), + "HalftoneType": Integer(16), + "Width": Integer(100), + "Height": Integer(100), + }, + ), + Content: []byte{}, + } + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func createPostScriptCalculatorFunctionStreamDict(xRefTable *XRefTable) (*IndirectRef, error) { + sd := &StreamDict{ + Dict: Dict( + map[string]Object{ + "FunctionType": Integer(4), + "Domain": NewNumberArray(100.), + "Range": NewNumberArray(100.), + }, + ), + Content: []byte{}, + } + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func addResources(xRefTable *XRefTable, pageDict Dict, fontName string) error { + fIndRef, err := createFontDict(xRefTable, fontName) + if err != nil { + return err + } + + functionalBasedShDict := createFunctionalShadingDict(xRefTable) + + radialShDict := createRadialShadingDict(xRefTable) + + f := Dict( + map[string]Object{ + "FunctionType": Integer(2), + "Domain": NewNumberArray(0.0, 1.0), + "C0": NewNumberArray(0.0), + "C1": NewNumberArray(1.0), + "N": Float(1), + }, + ) + + fontResources := Dict( + map[string]Object{ + "F1": *fIndRef, + }, + ) + + shadingResources := Dict( + map[string]Object{ + "S1": functionalBasedShDict, + "S3": radialShDict, + }, + ) + + colorSpaceResources := Dict( + map[string]Object{ + "CSCalGray": Array{ + Name("CalGray"), + Dict( + map[string]Object{ + "WhitePoint": NewNumberArray(0.9505, 1.0000, 1.0890), + }, + ), + }, + "CSCalRGB": Array{ + Name("CalRGB"), + Dict( + map[string]Object{ + "WhitePoint": NewNumberArray(0.9505, 1.0000, 1.0890), + }, + ), + }, + "CSLab": Array{ + Name("Lab"), + Dict( + map[string]Object{ + "WhitePoint": NewNumberArray(0.9505, 1.0000, 1.0890), + }, + ), + }, + "CS4DeviceN": Array{ + Name("DeviceN"), + NewNameArray("Orange", "Green", "None"), + Name("DeviceCMYK"), + f, + Dict( + map[string]Object{ + "Subtype": Name("DeviceN"), + }, + ), + }, + "CS6DeviceN": Array{ + Name("DeviceN"), + NewNameArray("L", "a", "b", "Spot1"), + Name("DeviceCMYK"), + f, + Dict( + map[string]Object{ + "Subtype": Name("NChannel"), + "Process": Dict( + map[string]Object{ + "ColorSpace": Array{ + Name("Lab"), + Dict( + map[string]Object{ + "WhitePoint": NewNumberArray(0.9505, 1.0000, 1.0890), + }, + ), + }, + "Components": NewNameArray("L", "a", "b"), + }, + ), + "Colorants": Dict( + map[string]Object{ + "Spot1": Array{ + Name("Separation"), + Name("Spot1"), + Name("DeviceCMYK"), + f, + }, + }, + ), + "MixingHints": Dict( + map[string]Object{ + "Solidities": Dict( + map[string]Object{ + "Spot1": Float(1.0), + }, + ), + "DotGain": Dict( + map[string]Object{ + "Spot1": f, + "Magenta": f, + "Yellow": f, + }, + ), + "PrintingOrder": NewNameArray("Magenta", "Yellow", "Spot1"), + }, + ), + }, + ), + }, + }, + ) + + anyXObject, err := createNormalAppearanceForFormField(xRefTable, 20., 20.) + if err != nil { + return err + } + + indRefHalfToneType6, err := createStreamObjForHalftoneDictType6(xRefTable) + if err != nil { + return err + } + + indRefHalfToneType10, err := createStreamObjForHalftoneDictType10(xRefTable) + if err != nil { + return err + } + + indRefHalfToneType16, err := createStreamObjForHalftoneDictType16(xRefTable) + if err != nil { + return err + } + + indRefFunctionStream, err := createPostScriptCalculatorFunctionStreamDict(xRefTable) + if err != nil { + return err + } + + graphicStateResources := Dict( + map[string]Object{ + "GS1": Dict( + map[string]Object{ + "Type": Name("ExtGState"), + "HT": Dict( + map[string]Object{ + "Type": Name("Halftone"), + "HalftoneType": Integer(1), + "Frequency": Integer(120), + "Angle": Integer(30), + "SpotFunction": Name("CosineDot"), + "TransferFunction": Name("Identity"), + }, + ), + "BM": NewNameArray("Overlay", "Darken", "Normal"), + "SMask": Dict( + map[string]Object{ + "Type": Name("Mask"), + "S": Name("Alpha"), + "G": *anyXObject, + "TR": f, + }, + ), + "TR": f, + "TR2": f, + }, + ), + "GS2": Dict( + map[string]Object{ + "Type": Name("ExtGState"), + "HT": Dict( + map[string]Object{ + "Type": Name("Halftone"), + "HalftoneType": Integer(5), + "Default": Dict( + map[string]Object{ + "Type": Name("Halftone"), + "HalftoneType": Integer(1), + "Frequency": Integer(120), + "Angle": Integer(30), + "SpotFunction": Name("CosineDot"), + "TransferFunction": Name("Identity"), + }, + ), + }, + ), + "BM": NewNameArray("Overlay", "Darken", "Normal"), + "SMask": Dict( + map[string]Object{ + "Type": Name("Mask"), + "S": Name("Alpha"), + "G": *anyXObject, + "TR": Name("Identity"), + }, + ), + "TR": Array{f, f, f, f}, + "TR2": Array{f, f, f, f}, + "BG2": f, + "UCR2": f, + "D": Array{Array{}, Integer(0)}, + }, + ), + "GS3": Dict( + map[string]Object{ + "Type": Name("ExtGState"), + "HT": *indRefHalfToneType6, + "SMask": Dict( + map[string]Object{ + "Type": Name("Mask"), + "S": Name("Alpha"), + "G": *anyXObject, + "TR": *indRefFunctionStream, + }, + ), + "BG2": *indRefFunctionStream, + "UCR2": *indRefFunctionStream, + "TR": *indRefFunctionStream, + "TR2": *indRefFunctionStream, + }, + ), + "GS4": Dict( + map[string]Object{ + "Type": Name("ExtGState"), + "HT": *indRefHalfToneType10, + }, + ), + "GS5": Dict( + map[string]Object{ + "Type": Name("ExtGState"), + "HT": *indRefHalfToneType16, + }, + ), + "GS6": Dict( + map[string]Object{ + "Type": Name("ExtGState"), + "HT": Dict( + map[string]Object{ + "Type": Name("Halftone"), + "HalftoneType": Integer(1), + "Frequency": Integer(120), + "Angle": Integer(30), + "SpotFunction": *indRefFunctionStream, + }, + ), + }, + ), + "GS7": Dict( + map[string]Object{ + "Type": Name("ExtGState"), + "HT": Dict( + map[string]Object{ + "Type": Name("Halftone"), + "HalftoneType": Integer(1), + "Frequency": Integer(120), + "Angle": Integer(30), + "SpotFunction": f, + }, + ), + }, + ), + }, + ) + + resourceDict := Dict( + map[string]Object{ + "Font": fontResources, + "Shading": shadingResources, + "ColorSpace": colorSpaceResources, + "ExtGState": graphicStateResources, + }, + ) + + pageDict.Insert("Resources", resourceDict) + + return nil +} + +// CreateTestPageContent draws a test grid. +func CreateTestPageContent(p Page) { + b := p.Buf + mb := p.MediaBox + + b.WriteString("[3]0 d 0 w ") + + // X + fmt.Fprintf(b, "0 0 m %f %f l s %f 0 m 0 %f l s ", + mb.Width(), mb.Height(), mb.Width(), mb.Height()) + + // Horizontal guides + c := 6 + if mb.Landscape() { + c = 4 + } + j := mb.Height() / float64(c) + for i := 1; i < c; i++ { + k := mb.Height() - float64(i)*j + s := fmt.Sprintf("0 %f m %f %f l s ", k, mb.Width(), k) + b.WriteString(s) + } + + // Vertical guides + c = 4 + if mb.Landscape() { + c = 6 + } + j = mb.Width() / float64(c) + for i := 1; i < c; i++ { + k := float64(i) * j + s := fmt.Sprintf("%f 0 m %f %f l s ", k, k, mb.Height()) + b.WriteString(s) + } +} + +func addContents(xRefTable *XRefTable, pageDict Dict, p Page) error { + CreateTestPageContent(p) + sd, _ := xRefTable.NewStreamDictForBuf(p.Buf.Bytes()) + + if err := sd.Encode(); err != nil { + return err + } + + ir, err := xRefTable.IndRefForNewObject(*sd) + if err != nil { + return err + } + + pageDict.Insert("Contents", *ir) + + return nil +} + +func createBoxColorDict() Dict { + cropBoxColorInfoDict := Dict( + map[string]Object{ + "C": NewNumberArray(1.0, 1.0, 0.0), + "W": Float(1.0), + "S": Name("D"), + "D": NewIntegerArray(3, 2), + }, + ) + bleedBoxColorInfoDict := Dict( + map[string]Object{ + "C": NewNumberArray(1.0, 0.0, 0.0), + "W": Float(3.0), + "S": Name("S"), + }, + ) + trimBoxColorInfoDict := Dict( + map[string]Object{ + "C": NewNumberArray(0.0, 1.0, 0.0), + "W": Float(1.0), + "S": Name("D"), + "D": NewIntegerArray(3, 2), + }, + ) + artBoxColorInfoDict := Dict( + map[string]Object{ + "C": NewNumberArray(0.0, 0.0, 1.0), + "W": Float(1.0), + "S": Name("S"), + }, + ) + d := Dict( + map[string]Object{ + "CropBox": cropBoxColorInfoDict, + "BleedBox": bleedBoxColorInfoDict, + "Trim": trimBoxColorInfoDict, + "ArtBox": artBoxColorInfoDict, + }, + ) + return d +} + +func addViewportDict(pageDict Dict) { + measureDict := Dict( + map[string]Object{ + "Type": Name("Measure"), + "Subtype": Name("RL"), + "R": StringLiteral("1in = 0.1m"), + "X": Array{ + Dict( + map[string]Object{ + "Type": Name("NumberFormat"), + "U": StringLiteral("mi"), + "C": Float(0.00139), + "D": Integer(100000), + }, + ), + }, + "D": Array{ + Dict( + map[string]Object{ + "Type": Name("NumberFormat"), + "U": StringLiteral("mi"), + "C": Float(1), + }, + ), + Dict( + map[string]Object{ + "Type": Name("NumberFormat"), + "U": StringLiteral("feet"), + "C": Float(5280), + }, + ), + Dict( + map[string]Object{ + "Type": Name("NumberFormat"), + "U": StringLiteral("inch"), + "C": Float(12), + "F": Name("F"), + "D": Integer(8), + }, + ), + }, + "A": Array{ + Dict( + map[string]Object{ + "Type": Name("NumberFormat"), + "U": StringLiteral("acres"), + "C": Float(640), + }, + ), + }, + "O": NewIntegerArray(0, 1), + }, + ) + + bbox := RectForDim(10, 60) + + vpDict := Dict( + map[string]Object{ + "Type": Name("Viewport"), + "BBox": bbox.Array(), + "Name": StringLiteral("viewPort"), + "Measure": measureDict, + }, + ) + + pageDict.Insert("VP", Array{vpDict}) +} + +func annotRect(i int, w, h, d, l float64) *Rectangle { + // d..distance between annotation rectangles + // l..side length of rectangle + + // max number of rectangles fitting into w + xmax := int((w - d) / (l + d)) + + // max number of rectangles fitting into h + ymax := int((h - d) / (l + d)) + + col := float64(i % xmax) + row := float64(i / xmax % ymax) + + llx := d + col*(l+d) + lly := d + row*(l+d) + + urx := llx + l + ury := lly + l + + return Rect(llx, lly, urx, ury) +} + +// createAnnotsArray generates side by side lined up annotations starting in the lower left corner of the page. +func createAnnotsArray(xRefTable *XRefTable, pageIndRef IndirectRef, mediaBox Array) (Array, error) { + pageWidth := mediaBox[2].(Float) + pageHeight := mediaBox[3].(Float) + + a := Array{} + + for i, f := range []func(*XRefTable, IndirectRef, Array) (*IndirectRef, error){ + createTextAnnotation, + createLinkAnnotation, + createFreeTextAnnotation, + createLineAnnotation, + createSquareAnnotation, + createCircleAnnotation, + createPolygonAnnotation, + createPolyLineAnnotation, + createHighlightAnnotation, + createUnderlineAnnotation, + createSquigglyAnnotation, + createStrikeOutAnnotation, + createCaretAnnotation, + createStampAnnotation, + createInkAnnotation, + createPopupAnnotation, + createFileAttachmentAnnotation, + createSoundAnnotation, + createMovieAnnotation, + createScreenAnnotation, + createWidgetAnnotation, + createPrinterMarkAnnotation, + createWaterMarkAnnotation, + create3DAnnotation, + createRedactAnnotation, + createLinkAnnotationWithRemoteGoToAction, + createLinkAnnotationWithEmbeddedGoToAction, + createLinkAnnotationDictWithLaunchAction, + createLinkAnnotationDictWithThreadAction, + createLinkAnnotationDictWithSoundAction, + createLinkAnnotationDictWithMovieAction, + createLinkAnnotationDictWithHideAction, + createTrapNetAnnotation, // must be the last annotation for this page! + } { + r := annotRect(i, pageWidth.Value(), pageHeight.Value(), 30, 80) + + ir, err := f(xRefTable, pageIndRef, r.Array()) + if err != nil { + return nil, err + } + + a = append(a, *ir) + } + + return a, nil +} + +func createPageWithAnnotations(xRefTable *XRefTable, parentPageIndRef IndirectRef, mediaBox *Rectangle, fontName string) (*IndirectRef, error) { + mba := mediaBox.Array() + + pageDict := Dict( + map[string]Object{ + "Type": Name("Page"), + "Parent": parentPageIndRef, + "BleedBox": mba, + "TrimBox": mba, + "ArtBox": mba, + "BoxColorInfo": createBoxColorDict(), + "UserUnit": Float(1.5)}, // Note: not honored by Apple Preview + ) + + err := addResources(xRefTable, pageDict, fontName) + if err != nil { + return nil, err + } + + p := Page{MediaBox: mediaBox, Buf: new(bytes.Buffer)} + err = addContents(xRefTable, pageDict, p) + if err != nil { + return nil, err + } + + pageIndRef, err := xRefTable.IndRefForNewObject(pageDict) + if err != nil { + return nil, err + } + + // Fake SeparationInfo related to a single page only. + separationInfoDict := Dict( + map[string]Object{ + "Pages": Array{*pageIndRef}, + "DeviceColorant": Name("Cyan"), + "ColorSpace": Array{ + Name("Separation"), + Name("Green"), + Name("DeviceCMYK"), + Dict( + map[string]Object{ + "FunctionType": Integer(2), + "Domain": NewNumberArray(0.0, 1.0), + "C0": NewNumberArray(0.0), + "C1": NewNumberArray(1.0), + "N": Float(1), + }, + ), + }, + }, + ) + pageDict.Insert("SeparationInfo", separationInfoDict) + + annotsArray, err := createAnnotsArray(xRefTable, *pageIndRef, mba) + if err != nil { + return nil, err + } + pageDict.Insert("Annots", annotsArray) + + addViewportDict(pageDict) + + return pageIndRef, nil +} + +func createPageWithAcroForm(xRefTable *XRefTable, parentPageIndRef IndirectRef, annotsArray Array, mediaBox *Rectangle, fontName string) (*IndirectRef, error) { + mba := mediaBox.Array() + + pageDict := Dict( + map[string]Object{ + "Type": Name("Page"), + "Parent": parentPageIndRef, + "BleedBox": mba, + "TrimBox": mba, + "ArtBox": mba, + "BoxColorInfo": createBoxColorDict(), + "UserUnit": Float(1.0), // Note: not honored by Apple Preview + }, + ) + + err := addResources(xRefTable, pageDict, fontName) + if err != nil { + return nil, err + } + + p := Page{MediaBox: mediaBox, Buf: new(bytes.Buffer)} + err = addContents(xRefTable, pageDict, p) + if err != nil { + return nil, err + } + + pageDict.Insert("Annots", annotsArray) + + return xRefTable.IndRefForNewObject(pageDict) +} + +func addPageTreeWithoutPage(xRefTable *XRefTable, rootDict Dict, d *Dim) error { + // May be modified later on. + mediaBox := RectForDim(d.Width, d.Height) + + pagesDict := Dict( + map[string]Object{ + "Type": Name("Pages"), + "Count": Integer(0), + "MediaBox": mediaBox.Array(), + }, + ) + + pagesDict.Insert("Kids", Array{}) + + pagesRootIndRef, err := xRefTable.IndRefForNewObject(pagesDict) + if err != nil { + return err + } + + rootDict.Insert("Pages", *pagesRootIndRef) + + return nil +} + +func addPageTreeWithSamplePage(xRefTable *XRefTable, rootDict Dict, p Page) error { + + // mediabox = physical page dimensions + mba := p.MediaBox.Array() + + pagesDict := Dict( + map[string]Object{ + "Type": Name("Pages"), + "Count": Integer(1), + "MediaBox": mba, + }, + ) + + parentPageIndRef, err := xRefTable.IndRefForNewObject(pagesDict) + if err != nil { + return err + } + + pageIndRef, err := createDemoPage(xRefTable, *parentPageIndRef, p) + if err != nil { + return err + } + + pagesDict.Insert("Kids", Array{*pageIndRef}) + rootDict.Insert("Pages", *parentPageIndRef) + + return nil +} + +func addPageTreeWithAnnotations(xRefTable *XRefTable, rootDict Dict, fontName string) (*IndirectRef, error) { + // mediabox = physical page dimensions + mediaBox := RectForFormat("A4") + mba := mediaBox.Array() + + pagesDict := Dict( + map[string]Object{ + "Type": Name("Pages"), + "Count": Integer(1), + "MediaBox": mba, + "CropBox": mba, + }, + ) + + parentPageIndRef, err := xRefTable.IndRefForNewObject(pagesDict) + if err != nil { + return nil, err + } + + pageIndRef, err := createPageWithAnnotations(xRefTable, *parentPageIndRef, mediaBox, fontName) + if err != nil { + return nil, err + } + + pagesDict.Insert("Kids", Array{*pageIndRef}) + rootDict.Insert("Pages", *parentPageIndRef) + + return pageIndRef, nil +} + +func addPageTreeWithAcroFields(xRefTable *XRefTable, rootDict Dict, annotsArray Array, fontName string) (*IndirectRef, error) { + // mediabox = physical page dimensions + mediaBox := RectForFormat("A4") + mba := mediaBox.Array() + + pagesDict := Dict( + map[string]Object{ + "Type": Name("Pages"), + "Count": Integer(1), + "MediaBox": mba, + "CropBox": mba, + }, + ) + + parentPageIndRef, err := xRefTable.IndRefForNewObject(pagesDict) + if err != nil { + return nil, err + } + + pageIndRef, err := createPageWithAcroForm(xRefTable, *parentPageIndRef, annotsArray, mediaBox, fontName) + if err != nil { + return nil, err + } + + pagesDict.Insert("Kids", Array{*pageIndRef}) + + rootDict.Insert("Pages", *parentPageIndRef) + + return pageIndRef, nil +} + +// create a thread with 2 beads. +func createThreadDict(xRefTable *XRefTable, pageIndRef IndirectRef) (*IndirectRef, error) { + infoDict := NewDict() + infoDict.InsertString("Title", "DummyArticle") + + d := Dict( + map[string]Object{ + "Type": Name("Thread"), + "I": infoDict, + }, + ) + + dIndRef, err := xRefTable.IndRefForNewObject(d) + if err != nil { + return nil, err + } + + // create first bead + d1 := Dict( + map[string]Object{ + "Type": Name("Bead"), + "T": *dIndRef, + "P": pageIndRef, + "R": NewNumberArray(0, 0, 100, 100), + }, + ) + + d1IndRef, err := xRefTable.IndRefForNewObject(d1) + if err != nil { + return nil, err + } + + d.Insert("F", *d1IndRef) + + // create last bead + d2 := Dict( + map[string]Object{ + "Type": Name("Bead"), + "T": *dIndRef, + "N": *d1IndRef, + "V": *d1IndRef, + "P": pageIndRef, + "R": NewNumberArray(0, 100, 200, 100), + }, + ) + + d2IndRef, err := xRefTable.IndRefForNewObject(d2) + if err != nil { + return nil, err + } + + d1.Insert("N", *d2IndRef) + d1.Insert("V", *d2IndRef) + + return dIndRef, nil +} + +func addThreads(xRefTable *XRefTable, rootDict Dict, pageIndRef IndirectRef) error { + ir, err := createThreadDict(xRefTable, pageIndRef) + if err != nil { + return err + } + + ir, err = xRefTable.IndRefForNewObject(Array{*ir}) + if err != nil { + return err + } + + rootDict.Insert("Threads", *ir) + + return nil +} + +func addOpenAction(xRefTable *XRefTable, rootDict Dict) error { + nextActionDict := Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("Movie"), + "T": StringLiteral("Sample Movie"), + }, + ) + + script := `app.alert('Hello Gopher!');` + + d := Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("JavaScript"), + "JS": StringLiteral(script), + "Next": nextActionDict, + }, + ) + + rootDict.Insert("OpenAction", d) + + return nil +} + +func addURI(xRefTable *XRefTable, rootDict Dict) { + d := NewDict() + d.InsertString("Base", "http://www.adobe.com") + + rootDict.Insert("URI", d) +} + +func addSpiderInfo(xRefTable *XRefTable, rootDict Dict) error { + // webCaptureInfoDict + webCaptureInfoDict := NewDict() + webCaptureInfoDict.InsertInt("V", 1.0) + + a := Array{} + captureCmdDict := NewDict() + captureCmdDict.InsertString("URL", ("")) + + cmdSettingsDict := NewDict() + captureCmdDict.Insert("S", cmdSettingsDict) + + ir, err := xRefTable.IndRefForNewObject(captureCmdDict) + if err != nil { + return err + } + + a = append(a, *ir) + + webCaptureInfoDict.Insert("C", a) + + ir, err = xRefTable.IndRefForNewObject(webCaptureInfoDict) + if err != nil { + return err + } + + rootDict.Insert("SpiderInfo", *ir) + + return nil +} + +func addOCProperties(xRefTable *XRefTable, rootDict Dict) error { + usageAppDict := Dict( + map[string]Object{ + "Event": Name("View"), + "OCGs": Array{}, // of indRefs + "Category": NewNameArray("Language"), + }, + ) + + optionalContentConfigDict := Dict( + map[string]Object{ + "Name": StringLiteral("OCConf"), + "Creator": StringLiteral("Horst Rutter"), + "BaseState": Name("ON"), + "OFF": Array{}, + "Intent": Name("Design"), + "AS": Array{usageAppDict}, + "Order": Array{}, + "ListMode": Name("AllPages"), + "RBGroups": Array{}, + "Locked": Array{}, + }, + ) + + d := Dict( + map[string]Object{ + "OCGs": Array{}, // of indRefs + "D": optionalContentConfigDict, + "Configs": Array{optionalContentConfigDict}, + }, + ) + + rootDict.Insert("OCProperties", d) + + return nil +} + +func addRequirements(xRefTable *XRefTable, rootDict Dict) { + d := NewDict() + d.InsertName("Type", "Requirement") + d.InsertName("S", "EnableJavaScripts") + + rootDict.Insert("Requirements", Array{d}) +} + +// CreateAnnotationDemoXRef creates a PDF file with examples of annotations and actions. +func CreateAnnotationDemoXRef() (*XRefTable, error) { + fontName := "Helvetica" + + xRefTable, err := createXRefTableWithRootDict() + if err != nil { + return nil, err + } + + rootDict, err := xRefTable.Catalog() + if err != nil { + return nil, err + } + + pageIndRef, err := addPageTreeWithAnnotations(xRefTable, rootDict, fontName) + if err != nil { + return nil, err + } + + err = addThreads(xRefTable, rootDict, *pageIndRef) + if err != nil { + return nil, err + } + + err = addOpenAction(xRefTable, rootDict) + if err != nil { + return nil, err + } + + addURI(xRefTable, rootDict) + + err = addSpiderInfo(xRefTable, rootDict) + if err != nil { + return nil, err + } + + err = addOCProperties(xRefTable, rootDict) + if err != nil { + return nil, err + } + + addRequirements(xRefTable, rootDict) + + return xRefTable, nil +} + +func setBit(i uint32, pos uint) uint32 { + // pos 1 == bit 0 + + var mask uint32 = 1 + + mask <<= pos - 1 + + i |= mask + + return i +} + +func createNormalAppearanceForFormField(xRefTable *XRefTable, w, h float64) (*IndirectRef, error) { + // stroke outline path + var b bytes.Buffer + fmt.Fprintf(&b, "0 0 m 0 %f l %f %f l %f 0 l s", h, w, h, w) + + sd := &StreamDict{ + Dict: Dict( + map[string]Object{ + "Type": Name("XObject"), + "Subtype": Name("Form"), + "FormType": Integer(1), + "BBox": NewNumberArray(0, 0, w, h), + "Matrix": NewIntegerArray(1, 0, 0, 1, 0, 0), + }, + ), + Content: b.Bytes(), + } + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func createRolloverAppearanceForFormField(xRefTable *XRefTable, w, h float64) (*IndirectRef, error) { + // stroke outline path + var b bytes.Buffer + fmt.Fprintf(&b, "1 0 0 RG 0 0 m 0 %f l %f %f l %f 0 l s", h, w, h, w) + + sd := &StreamDict{ + Dict: Dict( + map[string]Object{ + "Type": Name("XObject"), + "Subtype": Name("Form"), + "FormType": Integer(1), + "BBox": NewNumberArray(0, 0, w, h), + "Matrix": NewIntegerArray(1, 0, 0, 1, 0, 0), + }, + ), + Content: b.Bytes(), + } + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func createDownAppearanceForFormField(xRefTable *XRefTable, w, h float64) (*IndirectRef, error) { + // stroke outline path + var b bytes.Buffer + fmt.Fprintf(&b, "0 0 m 0 %f l %f %f l %f 0 l s", h, w, h, w) + + sd := &StreamDict{ + Dict: Dict( + map[string]Object{ + "Type": Name("XObject"), + "Subtype": Name("Form"), + "FormType": Integer(1), + "BBox": NewNumberArray(0, 0, w, h), + "Matrix": NewIntegerArray(1, 0, 0, 1, 0, 0), + }, + ), + Content: b.Bytes(), + } + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func createTextField(xRefTable *XRefTable, pageAnnots *Array, fontName string) (*IndirectRef, error) { + // lower left corner + x := 100.0 + y := 300.0 + + // width + w := 130.0 + + // height + h := 20.0 + + fN, err := createNormalAppearanceForFormField(xRefTable, w, h) + if err != nil { + return nil, err + } + + fR, err := createRolloverAppearanceForFormField(xRefTable, w, h) + if err != nil { + return nil, err + } + + fD, err := createDownAppearanceForFormField(xRefTable, w, h) + if err != nil { + return nil, err + } + + fontDict, err := createFontDict(xRefTable, fontName) + if err != nil { + return nil, err + } + + resourceDict := Dict( + map[string]Object{ + "Font": Dict( + map[string]Object{ + fontName: *fontDict, + }, + ), + }, + ) + + d := Dict( + map[string]Object{ + "AP": Dict( + map[string]Object{ + "N": *fN, + "R": *fR, + "D": *fD, + }, + ), + "DA": StringLiteral("/" + fontName + " 12 Tf 0 g"), + "DR": resourceDict, + "FT": Name("Tx"), + "Rect": NewNumberArray(x, y, x+w, y+h), + "Border": NewIntegerArray(0, 0, 1), + "Type": Name("Annot"), + "Subtype": Name("Widget"), + "T": StringLiteral("inputField"), + "TU": StringLiteral("inputField"), + "DV": StringLiteral("Default value"), + "V": StringLiteral("Default value"), + }, + ) + + ir, err := xRefTable.IndRefForNewObject(d) + if err != nil { + return nil, err + } + + *pageAnnots = append(*pageAnnots, *ir) + + return ir, nil +} + +func createYesAppearance(xRefTable *XRefTable, resourceDict Dict, w, h float64) (*IndirectRef, error) { + var b bytes.Buffer + fmt.Fprintf(&b, "q 0 0 1 rg BT /ZaDb 12 Tf 0 0 Td (8) Tj ET Q") + + sd := &StreamDict{ + Dict: Dict( + map[string]Object{ + "Resources": resourceDict, + "Subtype": Name("Form"), + "BBox": NewNumberArray(0, 0, w, h), + "OPI": Dict( + map[string]Object{ + "2.0": Dict( + map[string]Object{ + "Type": Name("OPI"), + "Version": Float(2.0), + "F": StringLiteral("Proxy"), + "Inks": Name("full_color"), + }, + ), + }, + ), + "Ref": Dict( + map[string]Object{ + "F": StringLiteral("Proxy"), + "Page": Integer(1), + }, + ), + }, + ), + Content: b.Bytes(), + } + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func createOffAppearance(xRefTable *XRefTable, resourceDict Dict, w, h float64) (*IndirectRef, error) { + var b bytes.Buffer + fmt.Fprintf(&b, "q 0 0 1 rg BT /ZaDb 12 Tf 0 0 Td (4) Tj ET Q") + + sd := &StreamDict{ + Dict: Dict( + map[string]Object{ + "Resources": resourceDict, + "Subtype": Name("Form"), + "BBox": NewNumberArray(0, 0, w, h), + "OPI": Dict( + map[string]Object{ + "1.3": Dict( + map[string]Object{ + "Type": Name("OPI"), + "Version": Float(1.3), + "F": StringLiteral("Proxy"), + "Size": NewIntegerArray(400, 400), + "CropRect": NewIntegerArray(0, 400, 400, 0), + "Position": NewNumberArray(0, 0, 0, 400, 400, 400, 400, 0), + }, + ), + }, + ), + }, + ), + Content: b.Bytes(), + } + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func createCheckBoxButtonField(xRefTable *XRefTable, pageAnnots *Array) (*IndirectRef, error) { + fontDict, err := createFontDict(xRefTable, "ZapfDingbats") + if err != nil { + return nil, err + } + + resDict := Dict( + map[string]Object{ + "Font": Dict( + map[string]Object{ + "ZaDb": *fontDict, + }, + ), + }, + ) + + yesForm, err := createYesAppearance(xRefTable, resDict, 20.0, 20.0) + if err != nil { + return nil, err + } + + offForm, err := createOffAppearance(xRefTable, resDict, 20.0, 20.0) + if err != nil { + return nil, err + } + + apDict := Dict( + map[string]Object{ + "N": Dict( + map[string]Object{ + "Yes": *yesForm, + "Off": *offForm, + }, + ), + }, + ) + + d := Dict( + map[string]Object{ + "FT": Name("Btn"), + "Rect": NewNumberArray(250, 300, 270, 320), + "Type": Name("Annot"), + "Subtype": Name("Widget"), + "T": StringLiteral("CheckBox"), + "TU": StringLiteral("CheckBox"), + "V": Name("Yes"), + "AS": Name("Yes"), + "AP": apDict, + }, + ) + + ir, err := xRefTable.IndRefForNewObject(d) + if err != nil { + return nil, err + } + + *pageAnnots = append(*pageAnnots, *ir) + + return ir, nil +} + +func createRadioButtonField(xRefTable *XRefTable, pageAnnots *Array) (*IndirectRef, error) { + var flags uint32 + flags = setBit(flags, 16) + + d := Dict( + map[string]Object{ + "FT": Name("Btn"), + "Ff": Integer(flags), + "Rect": NewNumberArray(250, 400, 280, 420), + //"Type": Name("Annot"), + //"Subtype": Name("Widget"), + "T": StringLiteral("Credit card"), + "V": Name("card1"), + }, + ) + + indRef, err := xRefTable.IndRefForNewObject(d) + if err != nil { + return nil, err + } + + fontDict, err := createFontDict(xRefTable, "ZapfDingbats") + if err != nil { + return nil, err + } + + resDict := Dict( + map[string]Object{ + "Font": Dict( + map[string]Object{ + "ZaDb": *fontDict, + }, + ), + }, + ) + + selectedForm, err := createYesAppearance(xRefTable, resDict, 20.0, 20.0) + if err != nil { + return nil, err + } + + offForm, err := createOffAppearance(xRefTable, resDict, 20.0, 20.0) + if err != nil { + return nil, err + } + + r1 := Dict( + map[string]Object{ + "Rect": NewNumberArray(250, 400, 280, 420), + "Type": Name("Annot"), + "Subtype": Name("Widget"), + "Parent": *indRef, + "T": StringLiteral("Radio1"), + "TU": StringLiteral("Radio1"), + "AS": Name("card1"), + "AP": Dict( + map[string]Object{ + "N": Dict( + map[string]Object{ + "card1": *selectedForm, + "Off": *offForm, + }, + ), + }, + ), + }, + ) + + indRefR1, err := xRefTable.IndRefForNewObject(r1) + if err != nil { + return nil, err + } + + r2 := Dict( + map[string]Object{ + "Rect": NewNumberArray(300, 400, 330, 420), + "Type": Name("Annot"), + "Subtype": Name("Widget"), + "Parent": *indRef, + "T": StringLiteral("Radio2"), + "TU": StringLiteral("Radio2"), + "AS": Name("Off"), + "AP": Dict( + map[string]Object{ + "N": Dict( + map[string]Object{ + "card2": *selectedForm, + "Off": *offForm, + }, + ), + }, + ), + }, + ) + + indRefR2, err := xRefTable.IndRefForNewObject(r2) + if err != nil { + return nil, err + } + + d.Insert("Kids", Array{*indRefR1, *indRefR2}) + + *pageAnnots = append(*pageAnnots, *indRefR1) + *pageAnnots = append(*pageAnnots, *indRefR2) + + return indRef, nil +} + +func createResetButton(xRefTable *XRefTable, pageAnnots *Array) (*IndirectRef, error) { + var flags uint32 + flags = setBit(flags, 17) + + fN, err := createNormalAppearanceForFormField(xRefTable, 20, 20) + if err != nil { + return nil, err + } + + resetFormActionDict := Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("ResetForm"), + "Fields": NewStringArray("inputField"), + "Flags": Integer(0), + }, + ) + + d := Dict( + map[string]Object{ + "FT": Name("Btn"), + "Ff": Integer(flags), + "Rect": NewNumberArray(100, 400, 120, 420), + "Type": Name("Annot"), + "Subtype": Name("Widget"), + "AP": Dict(map[string]Object{"N": *fN}), + "T": StringLiteral("Reset"), + "TU": StringLiteral("Reset"), + "A": resetFormActionDict, + }, + ) + + ir, err := xRefTable.IndRefForNewObject(d) + if err != nil { + return nil, err + } + + *pageAnnots = append(*pageAnnots, *ir) + + return ir, nil +} + +func createSubmitButton(xRefTable *XRefTable, pageAnnots *Array) (*IndirectRef, error) { + var flags uint32 + flags = setBit(flags, 17) + + fN, err := createNormalAppearanceForFormField(xRefTable, 20, 20) + if err != nil { + return nil, err + } + + urlSpec := Dict( + map[string]Object{ + "FS": Name("URL"), + "F": StringLiteral("http://www.me.com"), + }, + ) + + submitFormActionDict := Dict( + map[string]Object{ + "Type": Name("Action"), + "S": Name("SubmitForm"), + "F": urlSpec, + "Fields": NewStringArray("inputField"), + "Flags": Integer(0), + }, + ) + + d := Dict( + map[string]Object{ + "FT": Name("Btn"), + "Ff": Integer(flags), + "Rect": NewNumberArray(140, 400, 160, 420), + "Type": Name("Annot"), + "Subtype": Name("Widget"), + "AP": Dict(map[string]Object{"N": *fN}), + "T": StringLiteral("Submit"), + "TU": StringLiteral("Submit"), + "A": submitFormActionDict, + }, + ) + + ir, err := xRefTable.IndRefForNewObject(d) + if err != nil { + return nil, err + } + + *pageAnnots = append(*pageAnnots, *ir) + + return ir, nil +} + +func streamObjForXFAElement(xRefTable *XRefTable, s string) (*IndirectRef, error) { + sd := &StreamDict{ + Dict: Dict(map[string]Object{}), + Content: []byte(s), + } + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func createXFAArray(xRefTable *XRefTable) (Array, error) { + sd1, err := streamObjForXFAElement(xRefTable, "") + if err != nil { + return nil, err + } + + sd3, err := streamObjForXFAElement(xRefTable, "") + if err != nil { + return nil, err + } + + return Array{ + StringLiteral("xdp:xdp"), *sd1, + StringLiteral("/xdp:xdp"), *sd3, + }, nil +} + +func createAcroFormDict(xRefTable *XRefTable, fontName string) (Dict, Array, error) { + pageAnnots := Array{} + + text, err := createTextField(xRefTable, &pageAnnots, fontName) + if err != nil { + return nil, nil, err + } + + checkBox, err := createCheckBoxButtonField(xRefTable, &pageAnnots) + if err != nil { + return nil, nil, err + } + + radioButton, err := createRadioButtonField(xRefTable, &pageAnnots) + if err != nil { + return nil, nil, err + } + + resetButton, err := createResetButton(xRefTable, &pageAnnots) + if err != nil { + return nil, nil, err + } + + submitButton, err := createSubmitButton(xRefTable, &pageAnnots) + if err != nil { + return nil, nil, err + } + + xfaArr, err := createXFAArray(xRefTable) + if err != nil { + return nil, nil, err + } + + d := Dict( + map[string]Object{ + "Fields": Array{*text, *checkBox, *radioButton, *resetButton, *submitButton}, // indRefs of fieldDicts + "NeedAppearances": Boolean(true), + "CO": Array{*text}, + "XFA": xfaArr, + }, + ) + + return d, pageAnnots, nil +} + +// CreateAcroFormDemoXRef creates an xRefTable with an AcroForm example. +func CreateAcroFormDemoXRef() (*XRefTable, error) { + fontName := "Helvetica" + + xRefTable, err := createXRefTableWithRootDict() + if err != nil { + return nil, err + } + + rootDict, err := xRefTable.Catalog() + if err != nil { + return nil, err + } + + acroFormDict, annotsArray, err := createAcroFormDict(xRefTable, fontName) + if err != nil { + return nil, err + } + + rootDict.Insert("AcroForm", acroFormDict) + + _, err = addPageTreeWithAcroFields(xRefTable, rootDict, annotsArray, fontName) + if err != nil { + return nil, err + } + + rootDict.Insert("ViewerPreferences", + Dict( + map[string]Object{ + "FitWindow": Boolean(true), + "CenterWindow": Boolean(true), + }, + ), + ) + + return xRefTable, nil +} + +// CreateContext creates a Context for given cross reference table and configuration. +func CreateContext(xRefTable *XRefTable, conf *Configuration) *Context { + if conf == nil { + conf = NewDefaultConfiguration() + } + xRefTable.ValidationMode = conf.ValidationMode + return &Context{ + Configuration: conf, + XRefTable: xRefTable, + Write: NewWriteContext(conf.Eol), + } +} + +// CreateContextWithXRefTable creates a Context with an xRefTable without pages for given configuration. +func CreateContextWithXRefTable(conf *Configuration, pageDim *Dim) (*Context, error) { + xRefTable, err := createXRefTableWithRootDict() + if err != nil { + return nil, err + } + + rootDict, err := xRefTable.Catalog() + if err != nil { + return nil, err + } + + if err = addPageTreeWithoutPage(xRefTable, rootDict, pageDim); err != nil { + return nil, err + } + + return CreateContext(xRefTable, conf), nil +} + +func createDemoContentStreamDict(xRefTable *XRefTable, pageDict Dict, b []byte) (*IndirectRef, error) { + sd, _ := xRefTable.NewStreamDictForBuf(b) + if err := sd.Encode(); err != nil { + return nil, err + } + return xRefTable.IndRefForNewObject(*sd) +} + +func fontResources(xRefTable *XRefTable, fm FontMap) (Dict, error) { + + d := Dict{} + + for k, fontName := range fm { + ir, err := createFontDict(xRefTable, fontName) + if err != nil { + return nil, err + } + d.Insert(k, *ir) + } + + return d, nil +} + +func createDemoPage(xRefTable *XRefTable, parentPageIndRef IndirectRef, p Page) (*IndirectRef, error) { + + pageDict := Dict( + map[string]Object{ + "Type": Name("Page"), + "Parent": parentPageIndRef, + }, + ) + + fontRes, err := fontResources(xRefTable, p.Fm) + if err != nil { + return nil, err + } + + if len(fontRes) > 0 { + resDict := Dict( + map[string]Object{ + "Font": fontRes, + }, + ) + pageDict.Insert("Resources", resDict) + } + + ir, err := createDemoContentStreamDict(xRefTable, pageDict, p.Buf.Bytes()) + if err != nil { + return nil, err + } + pageDict.Insert("Contents", *ir) + + return xRefTable.IndRefForNewObject(pageDict) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/crypto.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/crypto.go new file mode 100644 index 0000000..99b5682 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/crypto.go @@ -0,0 +1,1519 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +// Functions dealing with PDF encryption. + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/md5" + "crypto/rand" + "crypto/rc4" + "crypto/sha256" + "encoding/binary" + "encoding/hex" + "fmt" + "io" + "strconv" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +var ( + pad = []byte{ + 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, + 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A, + } + + nullPad32 = make([]byte, 32) + + // Needed permission bits for pdfcpu commands. + perm = map[CommandMode]struct{ extract, modify int }{ + VALIDATE: {0, 0}, + OPTIMIZE: {0, 0}, + SPLIT: {1, 0}, + MERGECREATE: {0, 0}, + MERGEAPPEND: {0, 0}, + EXTRACTIMAGES: {1, 0}, + EXTRACTFONTS: {1, 0}, + EXTRACTPAGES: {1, 0}, + EXTRACTCONTENT: {1, 0}, + EXTRACTMETADATA: {1, 0}, + TRIM: {0, 1}, + LISTATTACHMENTS: {0, 0}, + EXTRACTATTACHMENTS: {1, 0}, + ADDATTACHMENTS: {0, 1}, + ADDATTACHMENTSPORTFOLIO: {0, 1}, + REMOVEATTACHMENTS: {0, 1}, + LISTPERMISSIONS: {0, 0}, + SETPERMISSIONS: {0, 0}, + ADDWATERMARKS: {0, 1}, + REMOVEWATERMARKS: {0, 1}, + INSERTPAGESBEFORE: {0, 1}, + INSERTPAGESAFTER: {0, 1}, + REMOVEPAGES: {0, 1}, + LISTKEYWORDS: {0, 0}, + ADDKEYWORDS: {0, 1}, + REMOVEKEYWORDS: {0, 1}, + LISTPROPERTIES: {0, 0}, + ADDPROPERTIES: {0, 1}, + REMOVEPROPERTIES: {0, 1}, + COLLECT: {1, 0}, + CROP: {0, 1}, + LISTBOXES: {0, 0}, + ADDBOXES: {0, 1}, + REMOVEBOXES: {0, 1}, + } +) + +// NewEncryptDict creates a new EncryptDict using the standard security handler. +func newEncryptDict(needAES bool, keyLength int, permissions int16) Dict { + + d := NewDict() + + d.Insert("Filter", Name("Standard")) + + if keyLength >= 128 { + d.Insert("Length", Integer(keyLength)) + i := 4 + if keyLength == 256 { + i = 5 + } + d.Insert("R", Integer(i)) + d.Insert("V", Integer(i)) + } else { + d.Insert("R", Integer(2)) + d.Insert("V", Integer(1)) + } + + // Set user access permission flags. + d.Insert("P", Integer(permissions)) + + d.Insert("StmF", Name("StdCF")) + d.Insert("StrF", Name("StdCF")) + + d1 := NewDict() + d1.Insert("AuthEvent", Name("DocOpen")) + + if needAES { + n := "AESV2" + if keyLength == 256 { + n = "AESV3" + } + d1.Insert("CFM", Name(n)) + } else { + d1.Insert("CFM", Name("V2")) + } + + d1.Insert("Length", Integer(keyLength/8)) + + d2 := NewDict() + d2.Insert("StdCF", d1) + + d.Insert("CF", d2) + + if keyLength == 256 { + d.Insert("U", NewHexLiteral(make([]byte, 48))) + d.Insert("O", NewHexLiteral(make([]byte, 48))) + d.Insert("UE", NewHexLiteral(make([]byte, 32))) + d.Insert("OE", NewHexLiteral(make([]byte, 32))) + d.Insert("Perms", NewHexLiteral(make([]byte, 16))) + } else { + d.Insert("U", NewHexLiteral(make([]byte, 32))) + d.Insert("O", NewHexLiteral(make([]byte, 32))) + } + + return d +} + +func encKey(userpw string, e *Enc) (key []byte) { + + // 2a + pw := []byte(userpw) + if len(pw) >= 32 { + pw = pw[:32] + } else { + pw = append(pw, pad[:32-len(pw)]...) + } + + // 2b + h := md5.New() + h.Write(pw) + + // 2c + h.Write(e.O) + + // 2d + var q = uint32(e.P) + h.Write([]byte{byte(q), byte(q >> 8), byte(q >> 16), byte(q >> 24)}) + + // 2e + h.Write(e.ID) + + // 2f + if e.R == 4 && !e.Emd { + h.Write([]byte{0xff, 0xff, 0xff, 0xff}) + } + + // 2g + key = h.Sum(nil) + + // 2h + if e.R >= 3 { + for i := 0; i < 50; i++ { + h.Reset() + h.Write(key[:e.L/8]) + key = h.Sum(nil) + } + } + + // 2i + if e.R >= 3 { + key = key[:e.L/8] + } else { + key = key[:5] + } + + return key +} + +// validateUserPassword validates the user password aka document open password. +func validateUserPassword(ctx *Context) (ok bool, err error) { + + if ctx.E.R == 5 { + return validateUserPasswordAES256(ctx) + } + + // Alg.4/5 p63 + // 4a/5a create encryption key using Alg.2 p61 + + u, key, err := u(ctx) + if err != nil { + return false, err + } + + ctx.EncKey = key + + switch ctx.E.R { + + case 2: + ok = bytes.Equal(ctx.E.U, u) + + case 3, 4: + ok = bytes.HasPrefix(ctx.E.U, u[:16]) + } + + return ok, nil +} + +func key(ownerpw, userpw string, r, l int) (key []byte) { + + // 3a + pw := []byte(ownerpw) + if len(pw) == 0 { + pw = []byte(userpw) + } + if len(pw) >= 32 { + pw = pw[:32] + } else { + pw = append(pw, pad[:32-len(pw)]...) + } + + // 3b + h := md5.New() + h.Write(pw) + key = h.Sum(nil) + + // 3c + if r >= 3 { + for i := 0; i < 50; i++ { + h.Reset() + h.Write(key) + key = h.Sum(nil) + } + } + + // 3d + if r >= 3 { + key = key[:l/8] + } else { + key = key[:5] + } + + return key +} + +// O calculates the owner password digest. +func o(ctx *Context) ([]byte, error) { + + ownerpw := ctx.OwnerPW + userpw := ctx.UserPW + + e := ctx.E + + // 3a-d + key := key(ownerpw, userpw, e.R, e.L) + + // 3e + o := []byte(userpw) + if len(o) >= 32 { + o = o[:32] + } else { + o = append(o, pad[:32-len(o)]...) + } + + // 3f + c, err := rc4.NewCipher(key) + if err != nil { + return nil, err + } + c.XORKeyStream(o, o) + + // 3g + if e.R >= 3 { + for i := 1; i <= 19; i++ { + keynew := make([]byte, len(key)) + copy(keynew, key) + + for j := range keynew { + keynew[j] ^= byte(i) + } + + c, err := rc4.NewCipher(keynew) + if err != nil { + return nil, err + } + c.XORKeyStream(o, o) + } + } + + return o, nil +} + +// U calculates the user password digest. +func u(ctx *Context) (u []byte, key []byte, err error) { + + // The PW string is generated from OS codepage characters by first converting the string to + // PDFDocEncoding. If input is Unicode, first convert to a codepage encoding , and then to + // PDFDocEncoding for backward compatibility. + userpw := ctx.UserPW + //fmt.Printf("U userpw=ctx.UserPW=%s\n", userpw) + + e := ctx.E + + key = encKey(userpw, e) + + c, err := rc4.NewCipher(key) + if err != nil { + return nil, nil, err + } + + switch e.R { + + case 2: + // 4b + u = make([]byte, 32) + copy(u, pad) + c.XORKeyStream(u, u) + + case 3, 4: + // 5b + h := md5.New() + h.Reset() + h.Write(pad) + + // 5c + h.Write(e.ID) + u = h.Sum(nil) + + // 5ds + c.XORKeyStream(u, u) + + // 5e + for i := 1; i <= 19; i++ { + keynew := make([]byte, len(key)) + copy(keynew, key) + + for j := range keynew { + keynew[j] ^= byte(i) + } + + c, err = rc4.NewCipher(keynew) + if err != nil { + return nil, nil, err + } + c.XORKeyStream(u, u) + } + } + + if len(u) < 32 { + u = append(u, nullPad32[:32-len(u)]...) + } + + return u, key, nil +} + +func validationSalt(bb []byte) []byte { + return bb[32:40] +} + +func keySalt(bb []byte) []byte { + return bb[40:] +} + +func validateOwnerPasswordAES256(ctx *Context) (ok bool, err error) { + + if len(ctx.OwnerPW) == 0 { + return false, nil + } + + // TODO Process PW with SASLPrep profile (RFC 4013) of stringprep (RFC 3454). + opw := []byte(ctx.OwnerPW) + if len(opw) > 127 { + opw = opw[:127] + } + //fmt.Printf("opw <%s> isValidUTF8String: %t\n", opw, utf8.Valid(opw)) + + // Algorithm 3.2a 3. + b := append(opw, validationSalt(ctx.E.O)...) + b = append(b, ctx.E.U...) + s := sha256.Sum256(b) + + if !bytes.HasPrefix(ctx.E.O, s[:]) { + return false, nil + } + + b = append(opw, keySalt(ctx.E.O)...) + b = append(b, ctx.E.U...) + key := sha256.Sum256(b) + + cb, err := aes.NewCipher(key[:]) + if err != nil { + return false, err + } + + iv := make([]byte, 16) + ctx.EncKey = make([]byte, 32) + + mode := cipher.NewCBCDecrypter(cb, iv) + mode.CryptBlocks(ctx.EncKey, ctx.E.OE) + + return true, nil +} + +func validateUserPasswordAES256(ctx *Context) (ok bool, err error) { + + // TODO Process PW with SASLPrep profile (RFC 4013) of stringprep (RFC 3454). + upw := []byte(ctx.UserPW) + if len(upw) > 127 { + upw = upw[:127] + } + //fmt.Printf("upw <%s> isValidUTF8String: %t\n", upw, utf8.Valid(upw)) + + // Algorithm 3.2a 4, + s := sha256.Sum256(append(upw, validationSalt(ctx.E.U)...)) + + if !bytes.HasPrefix(ctx.E.U, s[:]) { + return false, nil + } + + key := sha256.Sum256(append(upw, keySalt(ctx.E.U)...)) + + cb, err := aes.NewCipher(key[:]) + if err != nil { + return false, err + } + + iv := make([]byte, 16) + ctx.EncKey = make([]byte, 32) + + mode := cipher.NewCBCDecrypter(cb, iv) + mode.CryptBlocks(ctx.EncKey, ctx.E.UE) + + return true, nil +} + +// ValidateOwnerPassword validates the owner password aka change permissions password. +func validateOwnerPassword(ctx *Context) (ok bool, err error) { + + e := ctx.E + + if e.R == 5 { + return validateOwnerPasswordAES256(ctx) + } + + // The PW string is generated from OS codepage characters by first converting the string to + // PDFDocEncoding. If input is Unicode, first convert to a codepage encoding , and then to + // PDFDocEncoding for backward compatibility. + + ownerpw := ctx.OwnerPW + userpw := ctx.UserPW + + // 7a: Alg.3 p62 a-d + key := key(ownerpw, userpw, e.R, e.L) + + // 7b + upw := make([]byte, len(e.O)) + copy(upw, e.O) + + var c *rc4.Cipher + + switch e.R { + + case 2: + c, err = rc4.NewCipher(key) + if err != nil { + return + } + c.XORKeyStream(upw, upw) + + case 3, 4: + for i := 19; i >= 0; i-- { + + keynew := make([]byte, len(key)) + copy(keynew, key) + + for j := range keynew { + keynew[j] ^= byte(i) + } + + c, err = rc4.NewCipher(keynew) + if err != nil { + return false, err + } + + c.XORKeyStream(upw, upw) + } + } + + // Save user pw + upws := ctx.UserPW + + ctx.UserPW = string(upw) + ok, err = validateUserPassword(ctx) + + // Restore user pw + ctx.UserPW = upws + + return ok, err +} + +// SupportedCFEntry returns true if all entries found are supported. +func supportedCFEntry(d Dict) (bool, error) { + + cfm := d.NameEntry("CFM") + if cfm != nil && *cfm != "V2" && *cfm != "AESV2" && *cfm != "AESV3" { + return false, errors.New("pdfcpu: supportedCFEntry: invalid entry \"CFM\"") + } + + ae := d.NameEntry("AuthEvent") + if ae != nil && *ae != "DocOpen" { + return false, errors.New("pdfcpu: supportedCFEntry: invalid entry \"AuthEvent\"") + } + + l := d.IntEntry("Length") + if l != nil && (*l < 5 || *l > 16) && *l != 32 { + return false, errors.New("pdfcpu: supportedCFEntry: invalid entry \"Length\"") + } + + return cfm != nil && (*cfm == "AESV2" || *cfm == "AESV3"), nil +} + +func perms(p int) (list []string) { + + list = append(list, fmt.Sprintf("permission bits: %12b", uint32(p)&0x0F3C)) + list = append(list, fmt.Sprintf("Bit 3: %t (print(rev2), print quality(rev>=3))", p&0x0004 > 0)) + list = append(list, fmt.Sprintf("Bit 4: %t (modify other than controlled by bits 6,9,11)", p&0x0008 > 0)) + list = append(list, fmt.Sprintf("Bit 5: %t (extract(rev2), extract other than controlled by bit 10(rev>=3))", p&0x0010 > 0)) + list = append(list, fmt.Sprintf("Bit 6: %t (add or modify annotations)", p&0x0020 > 0)) + list = append(list, fmt.Sprintf("Bit 9: %t (fill in form fields(rev>=3)", p&0x0100 > 0)) + list = append(list, fmt.Sprintf("Bit 10: %t (extract(rev>=3))", p&0x0200 > 0)) + list = append(list, fmt.Sprintf("Bit 11: %t (modify(rev>=3))", p&0x0400 > 0)) + list = append(list, fmt.Sprintf("Bit 12: %t (print high-level(rev>=3))", p&0x0800 > 0)) + + return list +} + +// Permissions returns a list of set permissions. +func Permissions(ctx *Context) (list []string) { + + if ctx.E == nil { + return append(list, "Full access") + } + + return perms(ctx.E.P) +} + +func validatePermissions(ctx *Context) (bool, error) { + + // Algorithm 3.2a 5. + + if ctx.E.R != 5 { + return true, nil + } + + cb, err := aes.NewCipher(ctx.EncKey[:]) + if err != nil { + return false, err + } + + p := make([]byte, len(ctx.E.Perms)) + cb.Decrypt(p, ctx.E.Perms) + if string(p[9:12]) != "adb" { + return false, nil + } + + b := binary.LittleEndian.Uint32(p[:4]) + return int32(b) == int32(ctx.E.P), nil +} + +func writePermissions(ctx *Context, d Dict) error { + + // Algorithm 3.10 + + if ctx.E.R != 5 { + return nil + } + + b := make([]byte, 16) + binary.LittleEndian.PutUint64(b, uint64(ctx.E.P)) + + b[4] = 0xFF + b[5] = 0xFF + b[6] = 0xFF + b[7] = 0xFF + + var c byte = 'F' + if ctx.E.Emd { + c = 'T' + } + b[8] = c + + b[9] = 'a' + b[10] = 'd' + b[11] = 'b' + + cb, err := aes.NewCipher(ctx.EncKey[:]) + if err != nil { + return err + } + + cb.Encrypt(ctx.E.Perms, b) + d.Update("Perms", HexLiteral(hex.EncodeToString(ctx.E.Perms))) + + return nil +} + +func logP(enc *Enc) { + + for _, s := range perms(enc.P) { + log.Info.Println(s) + } + +} + +func maskExtract(mode CommandMode, secHandlerRev int) int { + + p, ok := perm[mode] + + // no permissions defined or don't need extract permission + if !ok || p.extract == 0 { + return 0 + } + + // need extract permission + + if secHandlerRev >= 3 { + return 0x0200 // need bit 10 + } + + return 0x0010 // need bit 5 +} + +func maskModify(mode CommandMode, secHandlerRev int) int { + + p, ok := perm[mode] + + // no permissions defined or don't need modify permission + if !ok || p.modify == 0 { + return 0 + } + + // need modify permission + + if secHandlerRev >= 3 { + return 0x0400 // need bit 11 + } + + return 0x0008 // need bit 4 +} + +// HasNeededPermissions returns true if permissions for pdfcpu processing are present. +func hasNeededPermissions(mode CommandMode, enc *Enc) bool { + + // see 7.6.3.2 + + logP(enc) + + m := maskExtract(mode, enc.R) + if m > 0 { + if enc.P&m == 0 { + return false + } + } + + m = maskModify(mode, enc.R) + if m > 0 { + if enc.P&m == 0 { + return false + } + } + + return true +} + +func getV(d Dict) (*int, error) { + + v := d.IntEntry("V") + + if v == nil || (*v != 1 && *v != 2 && *v != 4 && *v != 5) { + return nil, errors.Errorf("getV: \"V\" must be one of 1,2,4,5") + } + + return v, nil +} +func checkStmf(ctx *Context, stmf *string, cfDict Dict) error { + + if stmf != nil && *stmf != "Identity" { + + d := cfDict.DictEntry(*stmf) + if d == nil { + return errors.Errorf("pdfcpu: checkStmf: entry \"%s\" missing in \"CF\"", *stmf) + } + + aes, err := supportedCFEntry(d) + if err != nil { + return errors.Wrapf(err, "pdfcpu: checkStmv: unsupported \"%s\" entry in \"CF\"", *stmf) + } + ctx.AES4Streams = aes + } + + return nil +} + +func checkV(ctx *Context, d Dict) (*int, error) { + + v, err := getV(d) + if err != nil { + return nil, err + } + + // v == 2 implies RC4 + if *v != 4 && *v != 5 { + return v, nil + } + + // CF + cfDict := d.DictEntry("CF") + if cfDict == nil { + return nil, errors.Errorf("pdfcpu: checkV: required entry \"CF\" missing.") + } + + // StmF + stmf := d.NameEntry("StmF") + err = checkStmf(ctx, stmf, cfDict) + if err != nil { + return nil, err + } + + // StrF + strf := d.NameEntry("StrF") + if strf != nil && *strf != "Identity" { + d1 := cfDict.DictEntry(*strf) + if d1 == nil { + return nil, errors.Errorf("pdfcpu: checkV: entry \"%s\" missing in \"CF\"", *strf) + } + aes, err := supportedCFEntry(d1) + if err != nil { + return nil, errors.Wrapf(err, "checkV: unsupported \"%s\" entry in \"CF\"", *strf) + } + ctx.AES4Strings = aes + } + + // EFF + eff := d.NameEntry("EFF") + if eff != nil && *eff != "Identity" { + d := cfDict.DictEntry(*eff) + if d == nil { + return nil, errors.Errorf("pdfcpu: checkV: entry \"%s\" missing in \"CF\"", *eff) + } + aes, err := supportedCFEntry(d) + if err != nil { + return nil, errors.Wrapf(err, "checkV: unsupported \"%s\" entry in \"CF\"", *eff) + } + ctx.AES4EmbeddedStreams = aes + } + + return v, nil +} + +func length(d Dict) (int, error) { + + l := d.IntEntry("Length") + if l == nil { + return 40, nil + } + + if (*l < 40 || *l > 128 || *l%8 > 0) && *l != 256 { + return 0, errors.Errorf("pdfcpu: length: \"Length\" %d not supported\n", *l) + } + + return *l, nil +} + +func getR(d Dict) (int, error) { + + r := d.IntEntry("R") + if r == nil || *r < 2 || *r > 5 { + if *r > 5 { + return 0, errors.New("pdfcpu: PDF 2.0 encryption not supported") + } + return 0, errors.New("pdfcpu: encryption: \"R\" must be 2,3,4,5") + } + + return *r, nil +} + +func validateAlgorithm(ctx *Context) (ok bool) { + + k := ctx.EncryptKeyLength + + if ctx.EncryptUsingAES { + return k == 40 || k == 128 || k == 256 + } + + return k == 40 || k == 128 +} + +func validateAES256Parameters(d Dict) (oe, ue, perms []byte, err error) { + + for { + + // OE + oe, err = d.StringEntryBytes("OE") + if err != nil { + break + } + if oe == nil || len(oe) != 32 { + err = errors.New("pdfcpu: unsupported encryption: required entry \"OE\" missing or invalid") + break + } + + // UE + ue, err = d.StringEntryBytes("UE") + if err != nil { + break + } + if ue == nil || len(ue) != 32 { + err = errors.New("pdfcpu: unsupported encryption: required entry \"UE\" missing or invalid") + break + } + + // Perms + perms, err = d.StringEntryBytes("Perms") + if err != nil { + break + } + if perms == nil || len(perms) != 16 { + err = errors.New("pdfcpu: unsupported encryption: required entry \"Perms\" missing or invalid") + } + + break + } + + return oe, ue, perms, err +} + +func validateOAndU(d Dict) (o, u []byte, err error) { + + for { + + // O + o, err = d.StringEntryBytes("O") + if err != nil { + break + } + if o == nil || len(o) != 32 && len(o) != 48 { + err = errors.New("pdfcpu: unsupported encryption: required entry \"O\" missing or invalid") + break + } + + // U + u, err = d.StringEntryBytes("U") + if err != nil { + break + } + if u == nil || len(u) != 32 && len(u) != 48 { + err = errors.Errorf("pdfcpu: unsupported encryption: required entry \"U\" missing or invalid %d", len(u)) + } + + break + } + + return o, u, err +} + +// SupportedEncryption returns a pointer to a struct encapsulating used encryption. +func supportedEncryption(ctx *Context, d Dict) (*Enc, error) { + + // Filter + filter := d.NameEntry("Filter") + if filter == nil || *filter != "Standard" { + return nil, errors.New("pdfcpu: unsupported encryption: filter must be \"Standard\"") + } + + // SubFilter + if d.NameEntry("SubFilter") != nil { + return nil, errors.New("pdfcpu: unsupported encryption: \"SubFilter\" not supported") + } + + // V + v, err := checkV(ctx, d) + if err != nil { + return nil, err + } + + // Length + l, err := length(d) + if err != nil { + return nil, err + } + + // R + r, err := getR(d) + if err != nil { + return nil, err + } + + o, u, err := validateOAndU(d) + if err != nil { + return nil, err + } + + var oe, ue, perms []byte + if r == 5 { + oe, ue, perms, err = validateAES256Parameters(d) + if err != nil { + return nil, err + } + } + + // P + p := d.IntEntry("P") + if p == nil { + return nil, errors.New("pdfcpu: unsupported encryption: required entry \"P\" missing") + } + + // EncryptMetadata + encMeta := true + emd := d.BooleanEntry("EncryptMetadata") + if emd != nil { + encMeta = *emd + } + + return &Enc{ + O: o, + OE: oe, + U: u, + UE: ue, + L: l, + P: *p, + Perms: perms, + R: r, + V: *v, + Emd: encMeta}, + nil +} + +func decryptKey(objNumber, generation int, key []byte, aes bool) []byte { + + m := md5.New() + + nr := uint32(objNumber) + b1 := []byte{byte(nr), byte(nr >> 8), byte(nr >> 16)} + b := append(key, b1...) + + gen := uint16(generation) + b2 := []byte{byte(gen), byte(gen >> 8)} + b = append(b, b2...) + + m.Write(b) + + if aes { + m.Write([]byte("sAlT")) + } + + dk := m.Sum(nil) + + l := len(key) + 5 + if l < 16 { + dk = dk[:l] + } + + return dk +} + +// EncryptBytes encrypts s using RC4 or AES. +func encryptBytes(b []byte, objNr, genNr int, encKey []byte, needAES bool, r int) ([]byte, error) { + + if needAES { + k := encKey + if r != 5 { + k = decryptKey(objNr, genNr, encKey, needAES) + } + bb, err := encryptAESBytes(b, k) + if err != nil { + return nil, err + } + return bb, nil + } + + return applyRC4CipherBytes(b, objNr, genNr, encKey, needAES) +} + +// EncryptString encrypts s using RC4 or AES. +func encryptString(s string, objNr, genNr int, key []byte, needAES bool, r int) (*string, error) { + + b, err := encryptBytes([]byte(s), objNr, genNr, key, needAES, r) + if err != nil { + return nil, err + } + + s1, err := Escape(string(b)) + if err != nil { + return nil, err + } + + return s1, err +} + +// decryptBytes decrypts bb using RC4 or AES. +func decryptBytes(b []byte, objNr, genNr int, encKey []byte, needAES bool, r int) ([]byte, error) { + + if needAES { + k := encKey + if r != 5 { + k = decryptKey(objNr, genNr, encKey, needAES) + } + bb, err := decryptAESBytes(b, k) + if err != nil { + return nil, err + } + return bb, nil + } + + return applyRC4CipherBytes(b, objNr, genNr, encKey, needAES) +} + +// decryptString decrypts s using RC4 or AES. +func decryptString(s string, objNr, genNr int, key []byte, needAES bool, r int) (*string, error) { + + b, err := Unescape(s) + if err != nil { + return nil, err + } + + b, err = decryptBytes(b, objNr, genNr, key, needAES, r) + if err != nil { + return nil, err + } + + s1 := string(b) + return &s1, nil +} + +func applyRC4CipherBytes(b []byte, objNr, genNr int, key []byte, needAES bool) ([]byte, error) { + + c, err := rc4.NewCipher(decryptKey(objNr, genNr, key, needAES)) + if err != nil { + return nil, err + } + + c.XORKeyStream(b, b) + + return b, nil +} + +func encrypt(m map[string]Object, k string, v Object, objNr, genNr int, key []byte, needAES bool, r int) error { + + s, err := encryptDeepObject(v, objNr, genNr, key, needAES, r) + if err != nil { + return err + } + + if s != nil { + m[k] = *s + } + + return nil +} + +func encryptDict(d Dict, objNr, genNr int, key []byte, needAES bool, r int) error { + + for k, v := range d { + err := encrypt(d, k, v, objNr, genNr, key, needAES, r) + if err != nil { + return err + } + } + + return nil +} + +// EncryptDeepObject recurses over non trivial PDF objects and encrypts all strings encountered. +func encryptDeepObject(objIn Object, objNr, genNr int, key []byte, needAES bool, r int) (*HexLiteral, error) { + + _, ok := objIn.(IndirectRef) + if ok { + return nil, nil + } + + switch obj := objIn.(type) { + + case StreamDict: + err := encryptDict(obj.Dict, objNr, genNr, key, needAES, r) + if err != nil { + return nil, err + } + + case Dict: + err := encryptDict(obj, objNr, genNr, key, needAES, r) + if err != nil { + return nil, err + } + + case Array: + for i, v := range obj { + s, err := encryptDeepObject(v, objNr, genNr, key, needAES, r) + if err != nil { + return nil, err + } + if s != nil { + obj[i] = *s + } + } + + case StringLiteral: + s := obj.Value() + b, err := encryptBytes([]byte(s), objNr, genNr, key, needAES, r) + if err != nil { + return nil, err + } + hl := NewHexLiteral(b) + return &hl, nil + + case HexLiteral: + bb, err := encryptHexLiteral(obj, objNr, genNr, key, needAES, r) + if err != nil { + return nil, err + } + hl := NewHexLiteral(bb) + return &hl, nil + + default: + + } + + return nil, nil +} + +// DecryptDeepObject recurses over non trivial PDF objects and decrypts all strings encountered. +func decryptDeepObject(objIn Object, objNr, genNr int, key []byte, needAES bool, r int) (*StringLiteral, error) { + + _, ok := objIn.(IndirectRef) + if ok { + return nil, nil + } + + switch obj := objIn.(type) { + + case Dict: + for k, v := range obj { + s, err := decryptDeepObject(v, objNr, genNr, key, needAES, r) + if err != nil { + return nil, err + } + if s != nil { + obj[k] = *s + } + } + + case Array: + for i, v := range obj { + s, err := decryptDeepObject(v, objNr, genNr, key, needAES, r) + if err != nil { + return nil, err + } + if s != nil { + obj[i] = *s + } + } + + case StringLiteral: + s, err := decryptString(obj.Value(), objNr, genNr, key, needAES, r) + if err != nil { + return nil, err + } + sl := StringLiteral(*s) + return &sl, nil + + case HexLiteral: + bb, err := decryptHexLiteral(obj, objNr, genNr, key, needAES, r) + if err != nil { + return nil, err + } + sl := StringLiteral(string(bb)) + return &sl, nil + + default: + + } + + return nil, nil +} + +// EncryptStream encrypts a stream buffer using RC4 or AES. +func encryptStream(buf []byte, objNr, genNr int, encKey []byte, needAES bool, r int) ([]byte, error) { + + k := encKey + if r != 5 { + k = decryptKey(objNr, genNr, encKey, needAES) + } + + if needAES { + return encryptAESBytes(buf, k) + } + + return applyRC4Bytes(buf, k) +} + +// decryptStream decrypts a stream buffer using RC4 or AES. +func decryptStream(buf []byte, objNr, genNr int, encKey []byte, needAES bool, r int) ([]byte, error) { + + k := encKey + if r != 5 { + k = decryptKey(objNr, genNr, encKey, needAES) + } + + if needAES { + return decryptAESBytes(buf, k) + } + + return applyRC4Bytes(buf, k) +} + +func applyRC4Bytes(buf, key []byte) ([]byte, error) { + + c, err := rc4.NewCipher(key) + if err != nil { + return nil, err + } + + var b bytes.Buffer + + r := &cipher.StreamReader{S: c, R: bytes.NewReader(buf)} + + _, err = io.Copy(&b, r) + if err != nil { + return nil, err + } + + return b.Bytes(), nil +} + +func encryptAESBytes(b, key []byte) ([]byte, error) { + + // pad b to aes.Blocksize + l := len(b) % aes.BlockSize + c := 0x10 + if l > 0 { + c = aes.BlockSize - l + } + b = append(b, bytes.Repeat([]byte{byte(c)}, aes.BlockSize-l)...) + + if len(b) < aes.BlockSize { + return nil, errors.New("pdfcpu: encryptAESBytes: Ciphertext too short") + } + + if len(b)%aes.BlockSize > 0 { + return nil, errors.New("pdfcpu: encryptAESBytes: Ciphertext not a multiple of block size") + } + + data := make([]byte, aes.BlockSize+len(b)) + iv := data[:aes.BlockSize] + + _, err := io.ReadFull(rand.Reader, iv) + if err != nil { + return nil, err + } + + cb, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + mode := cipher.NewCBCEncrypter(cb, iv) + mode.CryptBlocks(data[aes.BlockSize:], b) + + return data, nil +} + +func decryptAESBytes(b, key []byte) ([]byte, error) { + + if len(b) < aes.BlockSize { + return nil, errors.New("pdfcpu: decryptAESBytes: Ciphertext too short") + } + + if len(b)%aes.BlockSize > 0 { + return nil, errors.New("pdfcpu: decryptAESBytes: Ciphertext not a multiple of block size") + } + + cb, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + iv := make([]byte, aes.BlockSize) + copy(iv, b[:aes.BlockSize]) + + data := b[aes.BlockSize:] + mode := cipher.NewCBCDecrypter(cb, iv) + mode.CryptBlocks(data, data) + + // Remove padding. + // Note: For some reason not all AES ciphertexts are padded. + if len(data) > 0 && data[len(data)-1] <= 0x10 { + e := len(data) - int(data[len(data)-1]) + data = data[:e] + } + + return data, nil +} + +func fileID(ctx *Context) (HexLiteral, error) { + + // see also 14.4 File Identifiers. + + // The calculation of the file identifier need not be reproducible; + // all that matters is that the identifier is likely to be unique. + // For example, two implementations of the preceding algorithm might use different formats for the current time, + // causing them to produce different file identifiers for the same file created at the same time, + // but the uniqueness of the identifier is not affected. + + h := md5.New() + + // Current timestamp. + h.Write([]byte(time.Now().String())) + + // File location - ignore, we don't have this. + + // File size. + h.Write([]byte(strconv.Itoa(ctx.Read.ReadFileSize()))) + + // All values of the info dict which is assumed to be there at this point. + d, err := ctx.DereferenceDict(*ctx.Info) + if err != nil { + return "", err + } + + for _, v := range d { + o, err := ctx.Dereference(v) + if err != nil { + return "", err + } + h.Write([]byte(o.String())) + } + + m := h.Sum(nil) + + return HexLiteral(hex.EncodeToString(m)), nil +} + +func encryptHexLiteral(hl HexLiteral, objNr, genNr int, key []byte, needAES bool, r int) ([]byte, error) { + + bb, err := hl.Bytes() + if err != nil { + return nil, err + } + + return encryptBytes(bb, objNr, genNr, key, needAES, r) +} + +func decryptHexLiteral(hl HexLiteral, objNr, genNr int, key []byte, needAES bool, r int) ([]byte, error) { + + bb, err := hl.Bytes() + if err != nil { + return nil, err + } + + return decryptBytes(bb, objNr, genNr, key, needAES, r) +} + +func calcFileEncKeyFromUE(ctx *Context) (k []byte, err error) { + + upw := []byte(ctx.OwnerPW) + key := sha256.Sum256(append(upw, keySalt(ctx.E.U)...)) + + cb, err := aes.NewCipher(key[:]) + if err != nil { + return nil, err + } + + iv := make([]byte, 16) + k = make([]byte, 32) + + mode := cipher.NewCBCDecrypter(cb, iv) + mode.CryptBlocks(k, ctx.E.UE) + + return k, nil +} + +func calcFileEncKeyFromOE(ctx *Context) (k []byte, err error) { + + opw := []byte(ctx.OwnerPW) + b := append(opw, keySalt(ctx.E.O)...) + b = append(b, ctx.E.U...) + key := sha256.Sum256(b) + + cb, err := aes.NewCipher(key[:]) + if err != nil { + return nil, err + } + + iv := make([]byte, 16) + k = make([]byte, 32) + + mode := cipher.NewCBCDecrypter(cb, iv) + mode.CryptBlocks(k, ctx.E.OE) + + return k, nil +} + +func calcFileEncKey(ctx *Context, d Dict) (err error) { + + // Calc Random UE (32 bytes) + ue := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, ue) + if err != nil { + return err + } + + ctx.E.UE = ue + d.Update("UE", HexLiteral(hex.EncodeToString(ctx.E.UE))) + + // Calc file encryption key. + ctx.EncKey, err = calcFileEncKeyFromUE(ctx) + + return err +} + +func calcOAndUAES256(ctx *Context, d Dict) (err error) { + + // 1) Calc U. + b := make([]byte, 16) + _, err = io.ReadFull(rand.Reader, b) + if err != nil { + return err + } + + u := append(make([]byte, 32), b...) + upw := []byte(ctx.UserPW) + h := sha256.Sum256(append(upw, validationSalt(u)...)) + ctx.E.U = append(h[:], b...) + d.Update("U", HexLiteral(hex.EncodeToString(ctx.E.U))) + + // 2) Calc O (depends on U). + b = make([]byte, 16) + _, err = io.ReadFull(rand.Reader, b) + if err != nil { + return err + } + + o := append(make([]byte, 32), b...) + opw := []byte(ctx.OwnerPW) + c := append(opw, validationSalt(o)...) + h = sha256.Sum256(append(c, ctx.E.U...)) + ctx.E.O = append(h[:], b...) + d.Update("O", HexLiteral(hex.EncodeToString(ctx.E.O))) + + err = calcFileEncKey(ctx, d) + if err != nil { + return err + } + + // Encrypt file encryption key into UE. + h = sha256.Sum256(append(upw, keySalt(u)...)) + cb, err := aes.NewCipher(h[:]) + if err != nil { + return err + } + + iv := make([]byte, 16) + mode := cipher.NewCBCEncrypter(cb, iv) + mode.CryptBlocks(ctx.E.UE, ctx.EncKey) + d.Update("UE", HexLiteral(hex.EncodeToString(ctx.E.UE))) + + // Encrypt file encryption key into OE. + c = append(opw, keySalt(o)...) + h = sha256.Sum256(append(c, ctx.E.U...)) + cb, err = aes.NewCipher(h[:]) + if err != nil { + return err + } + + mode = cipher.NewCBCEncrypter(cb, iv) + mode.CryptBlocks(ctx.E.OE, ctx.EncKey) + d.Update("OE", HexLiteral(hex.EncodeToString(ctx.E.OE))) + + return nil +} + +func calcOAndU(ctx *Context, d Dict) (err error) { + + if ctx.E.R == 5 { + return calcOAndUAES256(ctx, d) + } + + ctx.E.O, err = o(ctx) + if err != nil { + return err + } + + ctx.E.U, ctx.EncKey, err = u(ctx) + if err != nil { + return err + } + + d.Update("U", HexLiteral(hex.EncodeToString(ctx.E.U))) + d.Update("O", HexLiteral(hex.EncodeToString(ctx.E.O))) + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/date.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/date.go new file mode 100644 index 0000000..ef04202 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/date.go @@ -0,0 +1,367 @@ +/* +Copyright 2020 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + "strconv" + "strings" + "time" +) + +// DateString returns a string representation of t. +func DateString(t time.Time) string { + _, tz := t.Zone() + return fmt.Sprintf("D:%d%02d%02d%02d%02d%02d+%02d'%02d'", + t.Year(), t.Month(), t.Day(), + t.Hour(), t.Minute(), t.Second(), + tz/60/60, tz/60%60) +} + +func prevalidateDate(s string) (string, bool) { + // utf16 conversion if applicable. + if IsStringUTF16BE(s) { + utf16s, err := DecodeUTF16String(s) + if err != nil { + return "", false + } + s = utf16s + } + + // "D:YYYY" is mandatory + if len(s) < 6 { + return "", false + } + + return s, strings.HasPrefix(s, "D:") +} + +func parseTimezoneMinutes(s string, o byte) (int, bool) { + tzmin := s[20:22] + tzm, err := strconv.Atoi(tzmin) + if err != nil { + return 0, false + } + + if tzm > 59 { + return 0, false + } + + if o == 'Z' && tzm != 0 { + return 0, false + } + + // "D:YYYYMMDDHHmmSSZHH'mm" + if len(s) == 22 { + return 0, false + } + + // Accept a trailing ' + return tzm, s[22] == '\'' +} + +func validateTimezoneSeparator(c byte) bool { + return c == '+' || c == '-' || c == 'Z' +} + +func parseTimezone(s string) (h, m int, ok bool) { + o := s[16] + + if !validateTimezoneSeparator(o) { + return 0, 0, false + } + + // local time equal to UT. + // "D:YYYYMMDDHHmmSSZ" + if o == 'Z' && len(s) == 17 { + return 0, 0, true + } + + if len(s) < 20 { + return 0, 0, false + } + + neg := o == '-' + + tzhours := s[17:19] + tzh, err := strconv.Atoi(tzhours) + if err != nil { + return 0, 0, false + } + + if tzh > 23 { + return 0, 0, false + } + + if o == 'Z' && tzh != 0 { + return 0, 0, false + } + + if s[19] != '\'' { + return 0, 0, false + } + + if neg { + tzh *= -1 + } + + // "D:YYYYMMDDHHmmSSZHH'" + if len(s) == 20 { + return tzh, 0, true + } + + if len(s) != 22 && len(s) != 23 { + return 0, 0, false + } + + tzm, ok := parseTimezoneMinutes(s, o) + if !ok { + return 0, 0, false + } + + return tzh, tzm, true +} + +func parseYear(s string) (y int, finished, ok bool) { + year := s[2:6] + + y, err := strconv.Atoi(year) + if err != nil { + return 0, false, false + } + + // "D:YYYY" + if len(s) == 6 { + return y, true, true + } + + if len(s) == 7 { + return 0, false, false + } + + return y, false, true +} + +func parseMonth(s string) (m int, finished, ok bool) { + month := s[6:8] + + var err error + m, err = strconv.Atoi(month) + if err != nil { + return 0, false, false + } + + if m < 1 || m > 12 { + return 0, false, false + } + + // "D:YYYYMM" + if len(s) == 8 { + return m, true, true + } + + if len(s) == 9 { + return 0, false, false + } + + return m, false, true +} + +func parseDay(s string, y, m int) (d int, finished, ok bool) { + day := s[8:10] + + d, err := strconv.Atoi(day) + if err != nil { + return 0, false, false + } + + if d < 1 || d > 31 { + return 0, false, false + } + + // check valid Date(year,month,day) + // The day before the first day of next month: + t := time.Date(y, time.Month(m+1), 0, 0, 0, 0, 0, time.UTC) + if d > t.Day() { + return 0, false, false + } + + // "D:YYYYMMDD" + if len(s) == 10 { + return d, true, true + } + + if len(s) == 11 { + return 0, false, false + } + + return d, false, true +} + +func parseHour(s string) (h int, finished, ok bool) { + hour := s[10:12] + + h, err := strconv.Atoi(hour) + if err != nil { + return 0, false, false + } + + if h > 23 { + return 0, false, false + } + + // "D:YYYYMMDDHH" + if len(s) == 12 { + return h, true, true + } + + if len(s) == 13 { + return 0, false, false + } + + return h, false, true +} + +func parseMinute(s string) (min int, finished, ok bool) { + minute := s[12:14] + + min, err := strconv.Atoi(minute) + if err != nil { + return 0, false, false + } + + if min > 59 { + return 0, false, false + } + + // "D:YYYYMMDDHHmm" + if len(s) == 14 { + return min, true, true + } + + if len(s) == 15 { + return 0, false, false + } + + return min, false, true +} + +func parseSecond(s string) (sec int, finished, ok bool) { + second := s[14:16] + + sec, err := strconv.Atoi(second) + if err != nil { + return 0, false, false + } + + if sec > 59 { + return 0, false, false + } + + // "D:YYYYMMDDHHmmSS" + if len(s) == 16 { + return sec, true, true + } + + return sec, false, true +} + +// DateTime decodes s into a time.Time. +func DateTime(s string) (time.Time, bool) { + // 7.9.4 Dates + // (D:YYYYMMDDHHmmSSOHH'mm') + + var d time.Time + + var ok bool + s, ok = prevalidateDate(s) + if !ok { + return d, false + } + + y, finished, ok := parseYear(s) + if !ok { + return d, false + } + + // Construct time for yyyy 01 01 00:00:00 + d = time.Date(y, 1, 1, 0, 0, 0, 0, time.UTC) + if finished { + return d, true + } + + m, finished, ok := parseMonth(s) + if !ok { + return d, false + } + + d = d.AddDate(0, m-1, 0) + if finished { + return d, true + } + + day, finished, ok := parseDay(s, y, m) + if !ok { + return d, false + } + + d = d.AddDate(0, 0, day-1) + if finished { + return d, true + } + + h, finished, ok := parseHour(s) + if !ok { + return d, false + } + + d = d.Add(time.Duration(h) * time.Hour) + if finished { + return d, true + } + + min, finished, ok := parseMinute(s) + if !ok { + return d, false + } + + d = d.Add(time.Duration(min) * time.Minute) + if finished { + return d, true + } + + sec, finished, ok := parseSecond(s) + if !ok { + return d, false + } + + d = d.Add(time.Duration(sec) * time.Second) + if finished { + return d, true + } + + // Process timezone + tzh, tzm, ok := parseTimezone(s) + if !ok { + return d, false + } + + loc := time.FixedZone("", tzh*60*60+tzm*60) + d = time.Date(y, time.Month(m), day, h, min, sec, 0, loc) + + return d, true +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/dict.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/dict.go new file mode 100644 index 0000000..ad45688 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/dict.go @@ -0,0 +1,524 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + "sort" + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +// Dict represents a PDF dict object. +type Dict map[string]Object + +// NewDict returns a new PDFDict object. +func NewDict() Dict { + return map[string]Object{} +} + +// Len returns the length of this PDFDict. +func (d Dict) Len() int { + return len(d) +} + +// Clone returns a clone of d. +func (d Dict) Clone() Object { + d1 := NewDict() + for k, v := range d { + if v != nil { + v = v.Clone() + } + d1.Insert(k, v) + } + return d1 +} + +// Insert adds a new entry to this PDFDict. +func (d Dict) Insert(key string, value Object) (ok bool) { + _, found := d.Find(key) + if !found { + d[key] = value + } + return true +} + +// InsertInt adds a new int entry to this PDFDict. +func (d Dict) InsertInt(key string, value int) { + d.Insert(key, Integer(value)) +} + +// InsertFloat adds a new float entry to this PDFDict. +func (d Dict) InsertFloat(key string, value float32) { + d.Insert(key, Float(value)) +} + +// InsertString adds a new string entry to this PDFDict. +func (d Dict) InsertString(key, value string) { + d.Insert(key, StringLiteral(value)) +} + +// InsertName adds a new name entry to this PDFDict. +func (d Dict) InsertName(key, value string) { + d.Insert(key, Name(value)) +} + +// Update modifies an existing entry of this PDFDict. +func (d Dict) Update(key string, value Object) { + if value != nil { + d[key] = value + } +} + +// Find returns the Object for given key and PDFDict. +func (d Dict) Find(key string) (value Object, found bool) { + value, found = d[key] + return +} + +// Delete deletes the Object for given key. +func (d Dict) Delete(key string) (value Object) { + value, found := d.Find(key) + if !found { + return nil + } + delete(d, key) + return value +} + +// Entry returns the value for given key. +func (d Dict) Entry(dictName, key string, required bool) (Object, error) { + obj, found := d.Find(key) + if !found || obj == nil { + if required { + return nil, errors.Errorf("dict=%s required entry=%s missing", dictName, key) + } + //log.Trace.Printf("dict=%s entry %s is nil\n", dictName, key) + return nil, nil + } + return obj, nil +} + +// BooleanEntry expects and returns a BooleanEntry for given key. +func (d Dict) BooleanEntry(key string) *bool { + + value, found := d.Find(key) + if !found { + return nil + } + + bb, ok := value.(Boolean) + if ok { + b := bb.Value() + return &b + } + + return nil +} + +// StringEntry expects and returns a StringLiteral entry for given key. +func (d Dict) StringEntry(key string) *string { + + value, found := d.Find(key) + if !found { + return nil + } + + pdfStr, ok := value.(StringLiteral) + if ok { + s := string(pdfStr) + return &s + } + + return nil +} + +// NameEntry expects and returns a Name entry for given key. +func (d Dict) NameEntry(key string) *string { + + value, found := d.Find(key) + if !found { + return nil + } + + name, ok := value.(Name) + if ok { + s := name.Value() + return &s + } + + return nil +} + +// IntEntry expects and returns a Integer entry for given key. +func (d Dict) IntEntry(key string) *int { + + value, found := d.Find(key) + if !found { + return nil + } + + pdfInt, ok := value.(Integer) + if ok { + i := int(pdfInt) + return &i + } + + return nil +} + +// Int64Entry expects and returns a Integer entry representing an int64 value for given key. +func (d Dict) Int64Entry(key string) *int64 { + + value, found := d.Find(key) + if !found { + return nil + } + + pdfInt, ok := value.(Integer) + if ok { + i := int64(pdfInt) + return &i + } + + return nil +} + +// IndirectRefEntry returns an indirectRefEntry for given key for this dictionary. +func (d Dict) IndirectRefEntry(key string) *IndirectRef { + + value, found := d.Find(key) + if !found { + return nil + } + + pdfIndRef, ok := value.(IndirectRef) + if ok { + return &pdfIndRef + } + + // return err? + return nil +} + +// DictEntry expects and returns a PDFDict entry for given key. +func (d Dict) DictEntry(key string) Dict { + + value, found := d.Find(key) + if !found { + return nil + } + + // TODO resolve indirect ref. + + d, ok := value.(Dict) + if ok { + return d + } + + return nil +} + +// StreamDictEntry expects and returns a StreamDict entry for given key. +// unused. +func (d Dict) StreamDictEntry(key string) *StreamDict { + + value, found := d.Find(key) + if !found { + return nil + } + + sd, ok := value.(StreamDict) + if ok { + return &sd + } + + return nil +} + +// ArrayEntry expects and returns a Array entry for given key. +func (d Dict) ArrayEntry(key string) Array { + + value, found := d.Find(key) + if !found { + return nil + } + + a, ok := value.(Array) + if ok { + return a + } + + return nil +} + +// StringLiteralEntry returns a StringLiteral object for given key. +func (d Dict) StringLiteralEntry(key string) *StringLiteral { + + value, found := d.Find(key) + if !found { + return nil + } + + s, ok := value.(StringLiteral) + if ok { + return &s + } + + return nil +} + +// HexLiteralEntry returns a HexLiteral object for given key. +func (d Dict) HexLiteralEntry(key string) *HexLiteral { + + value, found := d.Find(key) + if !found { + return nil + } + + s, ok := value.(HexLiteral) + if ok { + return &s + } + + return nil +} + +// Length returns a *int64 for entry with key "Length". +// Stream length may be referring to an indirect object. +func (d Dict) Length() (*int64, *int) { + + val := d.Int64Entry("Length") + if val != nil { + return val, nil + } + + indirectRef := d.IndirectRefEntry("Length") + if indirectRef == nil { + return nil, nil + } + + intVal := indirectRef.ObjectNumber.Value() + + return nil, &intVal +} + +// Type returns the value of the name entry for key "Type". +func (d Dict) Type() *string { + return d.NameEntry("Type") +} + +// Subtype returns the value of the name entry for key "Subtype". +func (d Dict) Subtype() *string { + return d.NameEntry("Subtype") +} + +// Size returns the value of the int entry for key "Size" +func (d Dict) Size() *int { + return d.IntEntry("Size") +} + +// IsObjStm returns true if given PDFDict is an object stream. +func (d Dict) IsObjStm() bool { + return d.Type() != nil && *d.Type() == "ObjStm" +} + +// W returns a *Array for key "W". +func (d Dict) W() Array { + return d.ArrayEntry("W") +} + +// Prev returns the previous offset. +func (d Dict) Prev() *int64 { + return d.Int64Entry("Prev") +} + +// Index returns a *Array for key "Index". +func (d Dict) Index() Array { + return d.ArrayEntry("Index") +} + +// N returns a *int for key "N". +func (d Dict) N() *int { + return d.IntEntry("N") +} + +// First returns a *int for key "First". +func (d Dict) First() *int { + return d.IntEntry("First") +} + +// IsLinearizationParmDict returns true if this dict has an int entry for key "Linearized". +func (d Dict) IsLinearizationParmDict() bool { + return d.IntEntry("Linearized") != nil +} + +// IncrementBy increments the integer value for given key by i. +func (d *Dict) IncrementBy(key string, i int) error { + v := d.IntEntry(key) + if v == nil { + return errors.Errorf("IncrementBy: unknown key: %s", key) + } + *v += i + d.Update(key, Integer(*v)) + return nil +} + +// Increment increments the integer value for given key. +func (d *Dict) Increment(key string) error { + return d.IncrementBy(key, 1) +} + +func (d Dict) indentedString(level int) string { + + logstr := []string{"<<\n"} + tabstr := strings.Repeat("\t", level) + + var keys []string + for k := range d { + keys = append(keys, k) + } + sort.Strings(keys) + + for _, k := range keys { + + v := d[k] + + if subdict, ok := v.(Dict); ok { + dictStr := subdict.indentedString(level + 1) + logstr = append(logstr, fmt.Sprintf("%s<%s, %s>\n", tabstr, k, dictStr)) + continue + } + + if a, ok := v.(Array); ok { + arrStr := a.indentedString(level + 1) + logstr = append(logstr, fmt.Sprintf("%s<%s, %s>\n", tabstr, k, arrStr)) + continue + } + + logstr = append(logstr, fmt.Sprintf("%s<%s, %v>\n", tabstr, k, v)) + + } + + logstr = append(logstr, fmt.Sprintf("%s%s", strings.Repeat("\t", level-1), ">>")) + + return strings.Join(logstr, "") +} + +// PDFString returns a string representation as found in and written to a PDF file. +func (d Dict) PDFString() string { + + logstr := []string{} //make([]string, 20) + logstr = append(logstr, "<<") + + var keys []string + for k := range d { + keys = append(keys, k) + } + sort.Strings(keys) + + for _, k := range keys { + + v := d[k] + + if v == nil { + logstr = append(logstr, fmt.Sprintf("/%s null", k)) + continue + } + + d, ok := v.(Dict) + if ok { + logstr = append(logstr, fmt.Sprintf("/%s%s", k, d.PDFString())) + continue + } + + a, ok := v.(Array) + if ok { + logstr = append(logstr, fmt.Sprintf("/%s%s", k, a.PDFString())) + continue + } + + ir, ok := v.(IndirectRef) + if ok { + logstr = append(logstr, fmt.Sprintf("/%s %s", k, ir.PDFString())) + continue + } + + n, ok := v.(Name) + if ok { + logstr = append(logstr, fmt.Sprintf("/%s%s", k, n.PDFString())) + continue + } + + i, ok := v.(Integer) + if ok { + logstr = append(logstr, fmt.Sprintf("/%s %s", k, i.PDFString())) + continue + } + + f, ok := v.(Float) + if ok { + logstr = append(logstr, fmt.Sprintf("/%s %s", k, f.PDFString())) + continue + } + + b, ok := v.(Boolean) + if ok { + logstr = append(logstr, fmt.Sprintf("/%s %s", k, b.PDFString())) + continue + } + + sl, ok := v.(StringLiteral) + if ok { + logstr = append(logstr, fmt.Sprintf("/%s%s", k, sl.PDFString())) + continue + } + + hl, ok := v.(HexLiteral) + if ok { + logstr = append(logstr, fmt.Sprintf("/%s%s", k, hl.PDFString())) + continue + } + + log.Info.Fatalf("PDFDict.PDFString(): entry of unknown object type: %T %[1]v\n", v) + } + + logstr = append(logstr, ">>") + return strings.Join(logstr, "") +} + +func (d Dict) String() string { + return d.indentedString(1) +} + +// StringEntryBytes returns the byte slice representing the string value for key. +func (d Dict) StringEntryBytes(key string) ([]byte, error) { + + s := d.StringLiteralEntry(key) + if s != nil { + return Unescape(s.Value()) + } + + h := d.HexLiteralEntry(key) + if h != nil { + return h.Bytes() + } + + return nil, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/doc.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/doc.go new file mode 100644 index 0000000..1806de0 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/doc.go @@ -0,0 +1,39 @@ +/* + +Package pdfcpu is a PDF processing library written in Go supporting encryption. +It provides an API and a command line interface. Supported are all versions up to PDF 1.7 (ISO-32000). + +The commands are: + + attachments list, add, remove, extract embedded file attachments + boxes list, add, remove page boundaries for selected pages + changeopw change owner password + changeupw change user password + collect create custom sequence of selected pages + crop set cropbox for selected pages + decrypt remove password protection + encrypt set password protection + extract extract images, fonts, content, pages or metadata + fonts install, list supported fonts, create cheat sheets + grid rearrange pages or images for enhanced browsing experience + import import/convert images to PDF + info print file info + keywords list, add, remove keywords + merge concatenate PDFs + nup rearrange pages or images for reduced number of pages + optimize optimize PDF by getting rid of redundant page resources + pages insert, remove selected pages + paper print list of supported paper sizes + permissions list, set user access permissions + portfolio list, add, remove, extract portfolio entries with optional description + properties list, add, remove document properties + rotate rotate pages + split split up a PDF by span or bookmark + stamp add, remove, update Unicode text, image or PDF stamps for selected pages + trim create trimmed version of selected pages + validate validate PDF against PDF 32000-1:2008 (PDF 1.7) + version print version + watermark add, remove, update Unicode text, image or PDF watermarks for selected pages + +*/ +package pdfcpu diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/equal.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/equal.go new file mode 100644 index 0000000..01c25b0 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/equal.go @@ -0,0 +1,221 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bytes" + "fmt" + "strings" + + "github.com/pkg/errors" +) + +func equalObjects(o1, o2 Object, xRefTable *XRefTable) (ok bool, err error) { + + //log.Debug.Printf("equalObjects: comparing %T with %T \n", o1, o2) + + o1, err = xRefTable.Dereference(o1) + if err != nil { + return false, err + } + + o2, err = xRefTable.Dereference(o2) + if err != nil { + return false, err + } + + if o1 == nil { + return o2 != nil, nil + } + + o1Type := fmt.Sprintf("%T", o1) + o2Type := fmt.Sprintf("%T", o2) + //log.Debug.Printf("equalObjects: comparing dereferenced %s with %s \n", o1Type, o2Type) + + if o1Type != o2Type { + return false, nil + } + + switch o1.(type) { + + case Name, StringLiteral, HexLiteral, + Integer, Float, Boolean: + ok = o1 == o2 + + case Dict: + ok, err = equalDicts(o1.(Dict), o2.(Dict), xRefTable) + + case StreamDict: + sd1 := o1.(StreamDict) + sd2 := o2.(StreamDict) + ok, err = equalStreamDicts(&sd1, &sd2, xRefTable) + + case Array: + ok, err = equalArrays(o1.(Array), o2.(Array), xRefTable) + + default: + err = errors.Errorf("equalObjects: unhandled compare for type %s\n", o1Type) + } + + return ok, err +} + +func equalArrays(a1, a2 Array, xRefTable *XRefTable) (bool, error) { + + if len(a1) != len(a2) { + return false, nil + } + + for i, o1 := range a1 { + + ok, err := equalObjects(o1, a2[i], xRefTable) + if err != nil { + return false, err + } + + if !ok { + return false, nil + } + } + + return true, nil +} + +func equalStreamDicts(sd1, sd2 *StreamDict, xRefTable *XRefTable) (bool, error) { + + ok, err := equalDicts(sd1.Dict, sd2.Dict, xRefTable) + if err != nil { + return false, err + } + + if !ok { + return false, nil + } + + if sd1.Raw == nil || sd2 == nil { + return false, errors.New("pdfcpu: equalStreamDicts: stream dict not loaded") + } + + return bytes.Equal(sd1.Raw, sd2.Raw), nil +} + +func equalFontNames(v1, v2 Object, xRefTable *XRefTable) (bool, error) { + + v1, err := xRefTable.Dereference(v1) + if err != nil { + return false, err + } + bf1, ok := v1.(Name) + if !ok { + return false, errors.Errorf("equalFontNames: type cast problem") + } + + v2, err = xRefTable.Dereference(v2) + if err != nil { + return false, err + } + bf2 := v2.(Name) + if !ok { + return false, errors.Errorf("equalFontNames: type cast problem") + } + + // Ignore fontname prefix + i := strings.Index(string(bf1), "+") + if i > 0 { + bf1 = bf1[i+1:] + } + + i = strings.Index(string(bf2), "+") + if i > 0 { + bf2 = bf2[i+1:] + } + + //log.Debug.Printf("equalFontNames: bf1=%s fb2=%s\n", bf1, bf2) + + return bf1 == bf2, nil +} + +func equalDicts(d1, d2 Dict, xRefTable *XRefTable) (bool, error) { + + //log.Debug.Printf("equalDicts: %v\n%v\n", d1, d2) + + if d1.Len() != d2.Len() { + return false, nil + } + + for key, v1 := range d1 { + + v2, found := d2[key] + if !found { + //log.Debug.Printf("equalDict: return false, key=%s\n", key) + return false, nil + } + + // Special treatment for font dicts + if key == "BaseFont" || key == "FontName" || key == "Name" { + + ok, err := equalFontNames(v1, v2, xRefTable) + if err != nil { + //log.Debug.Printf("equalDict: return2 false, key=%s v1=%v\nv2=%v\n", key, v1, v2) + return false, err + } + + if !ok { + //log.Debug.Printf("equalDict: return3 false, key=%s v1=%v\nv2=%v\n", key, v1, v2) + return false, nil + } + + continue + } + + ok, err := equalObjects(v1, v2, xRefTable) + if err != nil { + //log.Debug.Printf("equalDict: return4 false, key=%s v1=%v\nv2=%v\n%v\n", key, v1, v2, err) + return false, err + } + + if !ok { + //log.Debug.Printf("equalDict: return5 false, key=%s v1=%v\nv2=%v\n", key, v1, v2) + return false, nil + } + + } + + //log.Debug.Println("equalDict: return true") + + return true, nil +} + +func equalFontDicts(fd1, fd2 Dict, xRefTable *XRefTable) (bool, error) { + + //log.Debug.Printf("equalFontDicts: %v\n%v\n", fd1, fd2) + + if fd1 == nil { + return fd2 == nil, nil + } + + if fd2 == nil { + return false, nil + } + + ok, err := equalDicts(fd1, fd2, xRefTable) + if err != nil { + return false, err + } + + return ok, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/extract.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/extract.go new file mode 100644 index 0000000..bcd0c9d --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/extract.go @@ -0,0 +1,337 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bytes" + "io" + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/filter" + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +// Image is a Reader representing an image resource. +type Image struct { + io.Reader + Name string // Resource name + Type string // File type +} + +// ImageObjNrs returns all image dict objNrs for pageNr. +// Requires an optimized context. +func (ctx *Context) ImageObjNrs(pageNr int) []int { + // TODO Exclude SMask image objects. + objNrs := []int{} + for k, v := range ctx.Optimize.PageImages[pageNr-1] { + if v { + objNrs = append(objNrs, k) + } + } + return objNrs +} + +// ExtractImage extracts an image from image dict referenced by objNr. +// Supported imgTypes: FlateDecode, DCTDecode, JPXDecode +func (ctx *Context) ExtractImage(objNr int) (*Image, error) { + imageObj := ctx.Optimize.ImageObjects[objNr] + + imageDict := imageObj.ImageDict + + fpl := imageDict.FilterPipeline + if fpl == nil { + return nil, nil + } + + var s []string + for _, filter := range fpl { + s = append(s, filter.Name) + } + filters := strings.Join(s, ",") + + // Ignore filter chains with length > 1 + if len(fpl) > 1 { + log.Info.Printf("ExtractImage(%d): skip img with more than 1 filter: %s\n", objNr, filters) + return nil, nil + } + + f := fpl[0].Name + + // We do not extract imageMasks with the exception of CCITTDecoded images + if im := imageDict.BooleanEntry("ImageMask"); im != nil && *im { + if f != filter.CCITTFax { + log.Info.Printf("ExtractImage(%d): skip img with imageMask\n", objNr) + return nil, nil + } + } + + // Ignore if image has a soft mask defined. + // if sm, _ := imageDict.Find("SMask"); sm != nil { + // log.Info.Printf("extractImageData: ignore obj# %d, unsupported \"SMask\"\n", objNr) + // return nil, nil + // } + + // Ignore if image has a Mask defined. + if sm, _ := imageDict.Find("Mask"); sm != nil { + log.Info.Printf("ExtractImage(%d): skip image, unsupported \"Mask\"\n", objNr) + return nil, nil + } + + // CCITTDecoded images sometimes don't have a ColorSpace attribute. + if f == filter.CCITTFax { + _, err := ctx.DereferenceDictEntry(imageDict.Dict, "ColorSpace") + if err != nil { + imageDict.InsertName("ColorSpace", DeviceGrayCS) + } + } + + switch f { + + case filter.Flate, filter.CCITTFax: + // If color space is CMYK then write .tif else write .png + if err := imageDict.Decode(); err != nil { + return nil, err + } + + case filter.DCT: + //imageObj.Extension = "jpg" + + case filter.JPX: + //imageObj.Extension = "jpx" + + default: + log.Debug.Printf("ExtractImage(%d): skip img, filter %s unsupported\n", objNr, filters) + return nil, nil + } + + return RenderImage(ctx.XRefTable, imageObj, objNr) +} + +// ExtractPageImages extracts all images used by pageNr. +func (ctx *Context) ExtractPageImages(pageNr int) ([]Image, error) { + ii := []Image{} + for _, objNr := range ctx.ImageObjNrs(pageNr) { + i, err := ctx.ExtractImage(objNr) + if err != nil { + return nil, err + } + if i != nil { + ii = append(ii, *i) + } + } + return ii, nil +} + +// Font is a Reader representing an embedded font. +type Font struct { + io.Reader + Name string + Type string +} + +// FontObjNrs returns all font dict objNrs for pageNr. +// Requires an optimized context. +func (ctx *Context) FontObjNrs(pageNr int) []int { + objNrs := []int{} + for k, v := range ctx.Optimize.PageFonts[pageNr-1] { + if v { + objNrs = append(objNrs, k) + } + } + return objNrs +} + +// ExtractFont extracts a font from font dict by objNr. +func (ctx *Context) ExtractFont(objNr int) (*Font, error) { + fontObject := ctx.Optimize.FontObjects[objNr] + + // Only embedded fonts have binary data. + if !fontObject.Embedded() { + log.Debug.Printf("ExtractFont: ignoring obj#%d - non embedded font: %s\n", objNr, fontObject.FontName) + return nil, nil + } + + d, err := fontDescriptor(ctx.XRefTable, fontObject.FontDict, objNr) + if err != nil { + return nil, err + } + + if d == nil { + log.Debug.Printf("ExtractFont: ignoring obj#%d - no fontDescriptor available for font: %s\n", objNr, fontObject.FontName) + return nil, nil + } + + ir := fontDescriptorFontFileIndirectObjectRef(d) + if ir == nil { + log.Debug.Printf("ExtractFont: ignoring obj#%d - no font file available for font: %s\n", objNr, fontObject.FontName) + return nil, nil + } + + var f *Font + + fontType := fontObject.SubType() + + switch fontType { + + case "TrueType": + // ttf ... true type file + // ttc ... true type collection + sd, _, err := ctx.DereferenceStreamDict(*ir) + if err != nil { + return nil, err + } + if sd == nil { + return nil, errors.Errorf("extractFontData: corrupt font obj#%d for font: %s\n", objNr, fontObject.FontName) + } + + // Decode streamDict if used filter is supported only. + err = sd.Decode() + if err == filter.ErrUnsupportedFilter { + return nil, nil + } + if err != nil { + return nil, err + } + + f = &Font{bytes.NewReader(sd.Content), fontObject.FontName, "ttf"} + + default: + log.Info.Printf("extractFontData: ignoring obj#%d - unsupported fonttype %s - font: %s\n", objNr, fontType, fontObject.FontName) + return nil, nil + } + + return f, nil +} + +// ExtractPageFonts extracts all fonts used by pageNr. +func (ctx *Context) ExtractPageFonts(pageNr int) ([]Font, error) { + ff := []Font{} + for _, i := range ctx.FontObjNrs(pageNr) { + f, err := ctx.ExtractFont(i) + if err != nil { + return nil, err + } + if f != nil { + ff = append(ff, *f) + } + } + return ff, nil +} + +// ExtractPage extracts pageNr into a new single page context. +func (ctx *Context) ExtractPage(pageNr int) (*Context, error) { + return ctx.ExtractPages([]int{pageNr}, false) +} + +// ExtractPages extracts pageNrs into a new single page context. +func (ctx *Context) ExtractPages(pageNrs []int, usePgCache bool) (*Context, error) { + ctxDest, err := CreateContextWithXRefTable(nil, PaperSize["A4"]) + if err != nil { + return nil, err + } + + if err := AddPages(ctx, ctxDest, pageNrs, usePgCache); err != nil { + return nil, err + } + + return ctxDest, nil +} + +// ExtractPageContent extracts the consolidated page content stream for pageNr. +func (ctx *Context) ExtractPageContent(pageNr int) (io.Reader, error) { + consolidateRes := false + d, _, err := ctx.PageDict(pageNr, consolidateRes) + if err != nil { + return nil, err + } + bb, err := ctx.PageContent(d) + if err != nil && err != errNoContent { + return nil, err + } + return bytes.NewReader(bb), nil +} + +// Metadata is a Reader representing a metadata dict. +type Metadata struct { + io.Reader // metadata + ObjNr int // metadata dict objNr + ParentObjNr int // container object number + ParentType string // container dict type +} + +func extractMetadataFromDict(ctx *Context, d Dict, parentObjNr int) (*Metadata, error) { + o, found := d.Find("Metadata") + if !found || o == nil { + return nil, nil + } + sd, _, err := ctx.DereferenceStreamDict(o) + if err != nil { + return nil, err + } + if sd == nil { + return nil, nil + } + // Get metadata dict object number. + ir, _ := o.(IndirectRef) + mdObjNr := ir.ObjectNumber.Value() + // Get container dict type. + dt := "unknown" + if d.Type() != nil { + dt = *d.Type() + } + // Decode streamDict for supported filters only. + if err = sd.Decode(); err == filter.ErrUnsupportedFilter { + return nil, nil + } + if err != nil { + return nil, err + } + return &Metadata{bytes.NewReader(sd.Content), mdObjNr, parentObjNr, dt}, nil +} + +// ExtractMetadata returns all metadata of ctx. +func (ctx *Context) ExtractMetadata() ([]Metadata, error) { + mm := []Metadata{} + for k, v := range ctx.Table { + if v.Free || v.Compressed { + continue + } + switch d := v.Object.(type) { + case Dict: + md, err := extractMetadataFromDict(ctx, d, k) + if err != nil { + return nil, err + } + if md == nil { + continue + } + mm = append(mm, *md) + + case StreamDict: + md, err := extractMetadataFromDict(ctx, d.Dict, k) + if err != nil { + return nil, err + } + if md == nil { + continue + } + mm = append(mm, *md) + } + } + return mm, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/fontDict.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/fontDict.go new file mode 100644 index 0000000..89c788b --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/fontDict.go @@ -0,0 +1,344 @@ +/* +Copyright 2020 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bytes" + "fmt" + "math/rand" + "sort" + "time" + "unicode/utf16" + + "github.com/pdfcpu/pdfcpu/pkg/font" + "github.com/pkg/errors" +) + +func flateEncodedStreamIndRef(xRefTable *XRefTable, data []byte) (*IndirectRef, error) { + sd, _ := xRefTable.NewStreamDictForBuf(data) + sd.InsertInt("Length1", len(data)) + if err := sd.Encode(); err != nil { + return nil, err + } + return xRefTable.IndRefForNewObject(*sd) +} + +func ttfFontFile(xRefTable *XRefTable, ttf font.TTFLight, fontName string) (*IndirectRef, error) { + bb, err := font.Read(fontName) + if err != nil { + return nil, err + } + return flateEncodedStreamIndRef(xRefTable, bb) +} + +func ttfSubFontFile(xRefTable *XRefTable, ttf font.TTFLight, fontName string) (*IndirectRef, error) { + bb, err := font.Subset(fontName, ttf.UsedGIDs) + if err != nil { + return nil, err + } + return flateEncodedStreamIndRef(xRefTable, bb) +} + +func coreFontDict(xRefTable *XRefTable, coreFontName string) (*IndirectRef, error) { + d := NewDict() + d.InsertName("Type", "Font") + d.InsertName("Subtype", "Type1") + d.InsertName("BaseFont", coreFontName) + if coreFontName != "Symbol" && coreFontName != "ZapfDingbats" { + d.InsertName("Encoding", "WinAnsiEncoding") + } + return xRefTable.IndRefForNewObject(d) +} + +func cidSet(xRefTable *XRefTable, ttf font.TTFLight) (*IndirectRef, error) { + bb := make([]byte, ttf.GlyphCount/8+1) + for gid := range ttf.UsedGIDs { + bb[gid/8] |= 1 << (7 - (gid % 8)) + } + return flateEncodedStreamIndRef(xRefTable, bb) +} + +func ttfFontDescriptorFlags(ttf font.TTFLight) uint32 { + // Bits: + // 1 FixedPitch + // 2 Serif + // 3 Symbolic + // 4 Script/cursive + // 6 Nonsymbolic + // 7 Italic + // 17 AllCap + + flags := uint32(0) + + // Bit 1 + //fmt.Printf("fixedPitch: %t\n", ttf.FixedPitch) + if ttf.FixedPitch { + flags |= 0x01 + } + + // Bit 6 Set for non symbolic + // Note: Symbolic fonts are unsupported. + flags |= 0x20 + + // Bit 7 + //fmt.Printf("italicAngle: %f\n", ttf.ItalicAngle) + if ttf.ItalicAngle != 0 { + flags |= 0x40 + } + + //fmt.Printf("flags: %08x\n", flags) + + return flags +} + +// CIDFontDescriptor represents a font descriptor describing +// the CIDFont’s default metrics other than its glyph widths. +func CIDFontDescriptor(xRefTable *XRefTable, ttf font.TTFLight, fontName, baseFontName string) (*IndirectRef, error) { + //fontFile, err := ttfFontFile(xRefTable, ttf, fontName) + fontFile, err := ttfSubFontFile(xRefTable, ttf, fontName) + if err != nil { + return nil, err + } + + cidSetIndRef, err := cidSet(xRefTable, ttf) + if err != nil { + return nil, err + } + + d := Dict( + map[string]Object{ + "Type": Name("FontDescriptor"), + "FontName": Name(baseFontName), + "Flags": Integer(ttfFontDescriptorFlags(ttf)), + "FontBBox": NewNumberArray(ttf.LLx, ttf.LLy, ttf.URx, ttf.URy), + "ItalicAngle": Float(ttf.ItalicAngle), + "Ascent": Integer(ttf.Ascent), + "Descent": Integer(ttf.Descent), + //"Leading": // The spacing between baselines of consecutive lines of text. + "CapHeight": Integer(ttf.CapHeight), + "StemV": Integer(70), // Irrelevant for embedded files. + "FontFile2": *fontFile, + + // (Optional) A dictionary containing entries that describe the style of the glyphs in the font (see 9.8.3.2, "Style"). + //"Style": Dict(map[string]Object{}), + + // (Optional) A name specifying the language of the font, which may be used for encodings + // where the language is not implied by the encoding itself. + //"Lang": Name(""), + + // (Optional) A dictionary whose keys identify a class of glyphs in a CIDFont. + // Each value shall be a dictionary containing entries that shall override the + // corresponding values in the main font descriptor dictionary for that class of glyphs (see 9.8.3.3, "FD"). + //"FD": Dict(map[string]Object{}), + + // (Optional) + // A stream identifying which CIDs are present in the CIDFont file. If this entry is present, + // the CIDFont shall contain only a subset of the glyphs in the character collection defined by the CIDSystemInfo dictionary. + // If it is absent, the only indication of a CIDFont subset shall be the subset tag in the FontName entry (see 9.6.4, "Font Subsets"). + // The stream’s data shall be organized as a table of bits indexed by CID. + // The bits shall be stored in bytes with the high-order bit first. Each bit shall correspond to a CID. + // The most significant bit of the first byte shall correspond to CID 0, the next bit to CID 1, and so on. + "CIDSet": *cidSetIndRef, + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +// CIDWidths returns the value for W in a CIDFontDict. +func CIDWidths(ttf font.TTFLight) Array { + gids := make([]int, 0, len(ttf.UsedGIDs)) + for gid := range ttf.UsedGIDs { + gids = append(gids, int(gid)) + } + sort.Ints(gids) + a := Array{} + for _, gid := range gids { + a = append(a, Integer(gid), Array{Integer(ttf.GlyphWidths[gid])}) + } + return a +} + +// CIDFontDict returns the descendant font dict for Type0 fonts. +func CIDFontDict(xRefTable *XRefTable, ttf font.TTFLight, fontName, baseFontName string) (*IndirectRef, error) { + fdIndRef, err := CIDFontDescriptor(xRefTable, ttf, fontName, baseFontName) + if err != nil { + return nil, err + } + + d := Dict( + map[string]Object{ + "Type": Name("Font"), + "Subtype": Name("CIDFontType2"), + "BaseFont": Name(baseFontName), + "CIDSystemInfo": Dict( + map[string]Object{ + "Ordering": StringLiteral("Identity"), + "Registry": StringLiteral("Adobe"), + "Supplement": Integer(0), + }, + ), + "FontDescriptor": *fdIndRef, + + // (Optional) + // The default width for glyphs in the CIDFont (see 9.7.4.3, "Glyph Metrics in CIDFonts"). + // Default value: 1000 (defined in user units). + "DW": Integer(1000), + + // (Optional) + // A description of the widths for the glyphs in the CIDFont. + // The array’s elements have a variable format that can specify individual widths for consecutive CIDs + // or one width for a range of CIDs (see 9.7.4.3, "Glyph Metrics in CIDFonts"). + // Default value: none (the DW value shall be used for all glyphs). + "W": CIDWidths(ttf), + + // (Optional; applies only to CIDFonts used for vertical writing) + // An array of two numbers specifying the default metrics for vertical writing (see 9.7.4.3, "Glyph Metrics in CIDFonts"). + // Default value: [880 −1000]. + // "DW2": Integer(1000), + + // (Optional; applies only to CIDFonts used for vertical writing) + // A description of the metrics for vertical writing for the glyphs in the CIDFont (see 9.7.4.3, "Glyph Metrics in CIDFonts"). + // Default value: none (the DW2 value shall be used for all glyphs). + // "W2": nil + + // (Optional; Type 2 CIDFonts only) + // A specification of the mapping from CIDs to glyph indices. + // maps CIDs to the glyph indices for the appropriate glyph descriptions in that font program. + // if stream: the glyph index for a particular CID value c shall be a 2-byte value stored in bytes 2 × c and 2 × c + 1, + // where the first byte shall be the high-order byte.)) + "CIDToGIDMap": Name("Identity"), + }, + ) + + return xRefTable.IndRefForNewObject(d) +} + +func bf(b *bytes.Buffer, ttf font.TTFLight) { + gids := make([]int, 0, len(ttf.UsedGIDs)) + for gid := range ttf.UsedGIDs { + gids = append(gids, int(gid)) + } + sort.Ints(gids) + + c := 100 + if len(gids) < 100 { + c = len(gids) + } + fmt.Fprintf(b, "%d beginbfchar\n", c) + for i := 0; i < len(gids); i++ { + fmt.Fprintf(b, "<%04X> <", gids[i]) + u := ttf.ToUnicode[uint16(gids[i])] + s := utf16.Encode([]rune{rune(u)}) + for _, v := range s { + fmt.Fprintf(b, "%04X", v) + } + fmt.Fprintf(b, ">\n") + if i > 0 && i%100 == 0 { + b.WriteString("endbfchar\n") + if len(gids)-i < 100 { + c = len(gids) - i + } + fmt.Fprintf(b, "%d beginbfchar\n", c) + } + } + b.WriteString("endbfchar\n") +} + +// toUnicodeCMap returns a stream dict containing a CMap file that maps character codes to Unicode values (see 9.10). +func toUnicodeCMap(xRefTable *XRefTable, ttf font.TTFLight, fontName string) (*IndirectRef, error) { + pro := `/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo << + /Registry (Adobe) + /Ordering (UCS) + /Supplement 0 +>> def +/CMapName /Adobe-Identity-UCS def +/CMapType 2 def +` + + r := `1 begincodespacerange +<0000> +endcodespacerange +` + + epi := `endcmap +CMapName currentdict /CMap defineresource pop +end +end` + + var b bytes.Buffer + b.WriteString(pro) + b.WriteString(r) + bf(&b, ttf) + b.WriteString(epi) + + return flateEncodedStreamIndRef(xRefTable, b.Bytes()) +} + +func subFontPrefix() string { + s := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + var r *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano())) + bb := make([]byte, 6) + for i := range bb { + bb[i] = s[r.Intn(len(s))] + } + return string(bb) +} + +func type0FontDict(xRefTable *XRefTable, fontName string) (*IndirectRef, error) { + // Combines a CIDFont and a CMap to produce a font whose glyphs may be accessed + // by means of variable-length character codes in a string to be shown. + ttf, ok := font.UserFontMetrics[fontName] + if !ok { + return nil, errors.Errorf("pdfcpu: font %s not available", fontName) + } + + baseFontName := subFontPrefix() + "-" + fontName + + descendentFontIndRef, err := CIDFontDict(xRefTable, ttf, fontName, baseFontName) + if err != nil { + return nil, err + } + + toUnicodeIndRef, err := toUnicodeCMap(xRefTable, ttf, fontName) + if err != nil { + return nil, err + } + + // Reset used glyph ids. + ttf.UsedGIDs = map[uint16]bool{} + + d := NewDict() + d.InsertName("Type", "Font") + d.InsertName("Subtype", "Type0") + d.InsertName("BaseFont", baseFontName) + d.InsertName("Encoding", "Identity-H") + d.Insert("DescendantFonts", Array{*descendentFontIndRef}) + d.Insert("ToUnicode", *toUnicodeIndRef) + + return xRefTable.IndRefForNewObject(d) +} + +func createFontDict(xRefTable *XRefTable, fontName string) (*IndirectRef, error) { + if font.IsCoreFont(fontName) { + return coreFontDict(xRefTable, fontName) + } + return type0FontDict(xRefTable, fontName) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/iccProfile.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/iccProfile.go new file mode 100644 index 0000000..6ec8b84 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/iccProfile.go @@ -0,0 +1,311 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "encoding/binary" + "encoding/hex" + "fmt" + + "github.com/pkg/errors" +) + +// ICC profiles are not yet supported! +// +// We fall back to the alternate color space and if there is none to whatever color space makes sense. + +//ICC profiles use big endian always. +type iccProfile struct { + b []byte + rX, rY, rZ float32 // redMatrixColumn; the first column in the matrix, which is used in matrix/TRC transforms. + gX, gY, gZ float32 // greenMatrixColumn; the second column in the matrix, which is used in matrix/TRC transforms. + bX, bY, bZ float32 // blueMatrixColumn; the third column in the matrix, which is used in matrix/TRC transforms. + //TRC = tone reproduction curve +} + +// header 128 bytes +// tagcount 4 bytes +// tagtable signature4, offset4, size4(%4=0) +// elements (required, optional, private) + +// dateTimeNumber 12 Bytes +// positionNumber offset 4 Bytes size 4 bytes +// response16Number +// s15Fixed16Number + +// elementdata 4byte boundary padding + +// required: +// profileDescriptionTag +// copyrightTag +// chromaticAdaptationTag + +// BToA0Tag *** +// AToB0Tag + +func (p iccProfile) tag(sig string) (int, int, error) { + + for i, j := 0, 132; i < p.tagCount(); i++ { + s := string(p.b[j : j+4]) + if s != sig { + j += 12 + continue + } + j += 4 + off := binary.BigEndian.Uint32(p.b[j:]) + j += 4 + size := binary.BigEndian.Uint32(p.b[j:]) + return int(off), int(size), nil + } + + return 0, 0, errors.Errorf("tag %s not found", sig) +} + +func (p *iccProfile) matrixCol(sig string) (float32, float32, float32, error) { + + off, size, err := p.tag(sig) + if err != nil { + return 0, 0, 0, err + } + + if size != 20 { + return 0, 0, 0, errors.Errorf("tag %s should have size 20, has:%d", sig, size) + } + + x, y, z := p.xyz(off + 8) + + return x, y, z, nil +} + +func (p *iccProfile) init() error { + + var err error + + p.rX, p.rY, p.rZ, err = p.matrixCol("rXYZ") + if err != nil { + return err + } + + p.gX, p.gY, p.gZ, err = p.matrixCol("gXYZ") + if err != nil { + return err + } + + p.bX, p.bY, p.bZ, err = p.matrixCol("bXYZ") + + return err +} + +func (p iccProfile) size() uint32 { + return binary.BigEndian.Uint32(p.b[0:]) +} + +func (p iccProfile) preferredCMM() string { + return string(p.b[4:8]) +} + +func (p iccProfile) version() string { + major := p.b[8] + minor := p.b[9] >> 4 + bugfix := p.b[9] & 0x0F + return fmt.Sprintf("%d.%d.%d.0", major, minor, bugfix) +} + +func (p iccProfile) class() string { + return string(p.b[12:16]) +} + +func (p iccProfile) dataColorSpace() string { + return string(p.b[16:20]) +} + +func (p iccProfile) pcs() string { + return string(p.b[20:24]) +} + +func (p iccProfile) creationTS() string { + + y := binary.BigEndian.Uint16(p.b[24:]) + m := binary.BigEndian.Uint16(p.b[26:]) + d := binary.BigEndian.Uint16(p.b[28:]) + h := binary.BigEndian.Uint16(p.b[30:]) + min := binary.BigEndian.Uint16(p.b[32:]) + s := binary.BigEndian.Uint16(p.b[34:]) + + return fmt.Sprintf("%4d-%02d-%02d %02d:%02d:%02d", y, m, d, h, min, s) +} + +func (p iccProfile) fileSig() string { + return string(p.b[36:40]) +} + +func (p iccProfile) primaryPlatform() string { + return string(p.b[40:44]) +} + +func (p iccProfile) deviceManufacturer() string { + return string(p.b[48:52]) +} + +func (p iccProfile) deviceModel() string { + return string(p.b[52:56]) +} + +func (p iccProfile) renderingIntent() string { + ri := binary.BigEndian.Uint16(p.b[66:]) + switch ri { + case 0: + return "Perceptual" + case 1: + return "Media-relative colorimetric" + case 2: + return "Saturation" + case 3: + return "ICC-absolute colorimetric" + + } + return "Perceptual" +} + +func (p iccProfile) xyz(i int) (x, y, z float32) { + + x = float32(binary.BigEndian.Uint16(p.b[i:])) + f := float32(binary.BigEndian.Uint16(p.b[i+2:])) / 0x10000 + if x < 0 { + x -= f + } else { + x += f + } + i += 4 + + y = float32(binary.BigEndian.Uint16(p.b[i:])) + f = float32(binary.BigEndian.Uint16(p.b[i+2:])) / 0x10000 + if y < 0 { + y -= f + } else { + y += f + } + i += 4 + + z = float32(binary.BigEndian.Uint16(p.b[i:])) + f = float32(binary.BigEndian.Uint16(p.b[i+2:])) / 0x10000 + if z < 0 { + z -= f + } else { + z += f + } + + return +} + +func (p iccProfile) PCSIlluminant() string { + + x, y, z := p.xyz(68) + + return fmt.Sprintf("X=%4.4f Y=%4.4f Z=%4.4f", x, y, z) +} + +func (p iccProfile) creator() string { + return string(p.b[80:84]) +} + +func (p iccProfile) id() string { + return hex.EncodeToString(p.b[84:100]) +} + +func (p iccProfile) tagCount() int { + return int(binary.BigEndian.Uint32(p.b[128:])) +} + +func (p iccProfile) String() string { + + // profile size: 4 bytes at offset 0 (uintt32) + s := fmt.Sprintf(""+ + " size: %d\n"+ + " preferredCMM: %s\n"+ + " version: %s\n"+ + " class: %s\n"+ + " dataCS: %s\n"+ + " pcs: %s\n"+ + " creationTS: %s\n"+ + " fileSig: %s\n"+ + " primPlatform: %s\n"+ + "deviceManufacturer: %s\n"+ + " deviceModel: %s\n"+ + " rendering intent: %s\n"+ + " PCS illuminant: %s\n"+ + " creator: %s\n"+ + " id: %s\n"+ + " tagCount: %d\n\n", + p.size(), + p.preferredCMM(), + p.version(), + p.class(), + p.dataColorSpace(), + p.pcs(), + p.creationTS(), + p.fileSig(), + p.primaryPlatform(), + p.deviceManufacturer(), + p.deviceModel(), + p.renderingIntent(), + p.PCSIlluminant(), + p.creator(), + p.id(), + p.tagCount(), + ) + + for i, j := 0, 132; i < p.tagCount(); i++ { + sig := string(p.b[j : j+4]) + j += 4 + off := binary.BigEndian.Uint32(p.b[j:]) + j += 4 + size := binary.BigEndian.Uint32(p.b[j:]) + j += 4 + s += fmt.Sprintf("Tag %d: signature:%s offset:%d(#%02x) size:%d(#%02x)\n%s\n", i, sig, off, off, size, size, hex.Dump(p.b[off:off+size])) + //s += fmt.Sprintf("Tag %d: signature:%s offset:%d(#%02x) size:%d(#%02x)\n", i, sig, off, off, size, size) + } + s += fmt.Sprintf("Matrix:\n") + s += fmt.Sprintf("%4.4f %4.4f %4.4f\n", p.rX, p.gX, p.bX) + s += fmt.Sprintf("%4.4f %4.4f %4.4f\n", p.rY, p.gY, p.bY) + s += fmt.Sprintf("%4.4f %4.4f %4.4f\n", p.rZ, p.gZ, p.bZ) + + // cprt copyrightTag multiLocalizedUnicodeType contains the text copyright information for the profile. + // desc profileDescriptionTag multiLocalizedUnicodeType describes the structure containing invariant and localizable versions of the profile description for display. => 10.13 + + // wtpt mediaWhitePointTag XYZType used for generating the ICC-absolute colorimetric intent, specifies the chromatically adapted nCIEXYZ tristimulus values of the media white point. + // bkpt + + // rXYZ XYZType redMatrixColumnTag contains the first column in the matrix used in matrix/TRC transforms. + // gXYZ XYZType greenMatrixColumnTag contains the second column in the matrix used in matrix/TRC transforms. + // bXYZ XYZType blueMatrixColumnTag contains the third column in the matrix used in matrix/TRC transforms. + + // rTRC curveType or parametricCurveType redTRCTag contains the red channel tone reproduction curve. f(device)=linear + // gTRC curveType or parametricCurveType greenTRCTag contains the green channel tone reproduction curve. + // bTRC curveType or parametricCurveType blueTRCTag contains the blue channel tone reproduction curve. + + // dmnd deviceMfgDescTag multiLocalizedUnicodeType describes the structure containing invariant and localizable versions of the device manufacturer for display. => 10.13 + // dmdd deviceModelDescTag multiLocalizedUnicodeType describes the structure containing invariant and localizable versions of the device model for display. => 10.13 + // vued viewingCondDescTag describes the structure containing invariant and localizable versions of the viewing conditions. => 10.13 + + // view viewingConditionsTag viewingConditionsType defines the viewing conditions parameters. => 10.28 + // lumi luminanceTag XYZType contains the absolute luminance of emissive devices in candelas per square metre as described by the Y channel. + // meas measurementTag measurementType describes the alternative measurement specification, such as a D65 illuminant instead of the default D50. + // tech technologyTag signatureType => table 29 + + return s +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/importImage.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/importImage.go new file mode 100644 index 0000000..2251c3e --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/importImage.go @@ -0,0 +1,482 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bytes" + "fmt" + "io" + "strconv" + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/types" + "github.com/pkg/errors" +) + +type importParamMap map[string]func(string, *Import) error + +// Handle applies parameter completion and if successful +// parses the parameter values into import. +func (m importParamMap) Handle(paramPrefix, paramValueStr string, imp *Import) error { + + var param string + + // Completion support + for k := range m { + if !strings.HasPrefix(k, paramPrefix) { + continue + } + if len(param) > 0 { + return errors.Errorf("pdfcpu: ambiguous parameter prefix \"%s\"", paramPrefix) + } + param = k + } + + if param == "" { + return errors.Errorf("pdfcpu: unknown parameter prefix \"%s\"", paramPrefix) + } + + return m[param](paramValueStr, imp) +} + +var impParamMap = importParamMap{ + "dimensions": parseDimensionsImp, + "dpi": parseDPI, + "formsize": parsePageFormatImp, + "papersize": parsePageFormatImp, + "position": parsePositionAnchorImp, + "offset": parsePositionOffsetImp, + "scalefactor": parseScaleFactorImp, +} + +// Import represents the command details for the command "ImportImage". +type Import struct { + PageDim *Dim // page dimensions in display unit. + PageSize string // one of A0,A1,A2,A3,A4(=default),A5,A6,A7,A8,Letter,Legal,Ledger,Tabloid,Executive,ANSIC,ANSID,ANSIE. + UserDim bool // true if one of dimensions or paperSize provided overriding the default. + DPI int // destination resolution to apply in dots per inch. + Pos anchor // position anchor, one of tl,tc,tr,l,c,r,bl,bc,br,full. + Dx, Dy int // anchor offset. + Scale float64 // relative scale factor. 0 <= x <= 1 + ScaleAbs bool // true for absolute scaling. + InpUnit DisplayUnit // input display unit. +} + +// DefaultImportConfig returns the default configuration. +func DefaultImportConfig() *Import { + return &Import{ + PageDim: PaperSize["A4"], + PageSize: "A4", + Pos: Full, + Scale: 0.5, + InpUnit: POINTS, + } +} + +func (imp Import) String() string { + + sc := "relative" + if imp.ScaleAbs { + sc = "absolute" + } + + return fmt.Sprintf("Import conf: %s %s, pos=%s, dx=%d, dy=%d, scaling: %.1f %s\n", + imp.PageSize, *imp.PageDim, imp.Pos, imp.Dx, imp.Dy, imp.Scale, sc) +} + +func parsePageFormat(v string) (*Dim, string, error) { + + // Optional: appended last letter L indicates landscape mode. + // Optional: appended last letter P indicates portrait mode. + // eg. A4L means A4 in landscape mode whereas A4 defaults to A4P + // The default mode is defined implicitly via PaperSize dimensions. + + var land, port bool + + if strings.HasSuffix(v, "L") { + v = v[:len(v)-1] + land = true + } else if strings.HasSuffix(v, "P") { + v = v[:len(v)-1] + port = true + } + + d, ok := PaperSize[v] + if !ok { + return nil, v, errors.Errorf("pdfcpu: page format %s is unsupported.\n", v) + } + + if d.Portrait() && land || d.Landscape() && port { + d.Width, d.Height = d.Height, d.Width + } + + return d, v, nil +} + +func parsePageFormatImp(s string, imp *Import) (err error) { + if imp.UserDim { + return errors.New("pdfcpu: only one of formsize(papersize) or dimensions allowed") + } + imp.PageDim, imp.PageSize, err = parsePageFormat(s) + imp.UserDim = true + return err +} + +func parsePageDim(v string, u DisplayUnit) (*Dim, string, error) { + + ss := strings.Split(v, " ") + if len(ss) != 2 { + return nil, v, errors.Errorf("pdfcpu: illegal dimension string: need 2 positive values, %s\n", v) + } + + w, err := strconv.ParseFloat(ss[0], 64) + if err != nil || w <= 0 { + return nil, v, errors.Errorf("pdfcpu: dimension X must be a positiv numeric value: %s\n", ss[0]) + } + + h, err := strconv.ParseFloat(ss[1], 64) + if err != nil || h <= 0 { + return nil, v, errors.Errorf("pdfcpu: dimension Y must be a positiv numeric value: %s\n", ss[1]) + } + + d := Dim{toUserSpace(w, u), toUserSpace(h, u)} + + return &d, "", nil +} + +func parseDimensionsImp(s string, imp *Import) (err error) { + if imp.UserDim { + return errors.New("pdfcpu: only one of formsize(papersize) or dimensions allowed") + } + imp.PageDim, imp.PageSize, err = parsePageDim(s, imp.InpUnit) + imp.UserDim = true + return err +} + +type anchor int + +func (a anchor) String() string { + + switch a { + + case TopLeft: + return "top left" + + case TopCenter: + return "top center" + + case TopRight: + return "top right" + + case Left: + return "left" + + case Center: + return "center" + + case Right: + return "right" + + case BottomLeft: + return "bottom left" + + case BottomCenter: + return "bottom center" + + case BottomRight: + return "bottom right" + + case Full: + return "full" + + } + + return "" +} + +// These are the defined anchors for relative positioning. +const ( + TopLeft anchor = iota + TopCenter + TopRight + Left + Center // default + Right + BottomLeft + BottomCenter + BottomRight + Full // special case, no anchor needed, imageSize = pageSize +) + +func parsePositionAnchor(s string) (anchor, error) { + var a anchor + switch s { + case "tl": + a = TopLeft + case "tc": + a = TopCenter + case "tr": + a = TopRight + case "l": + a = Left + case "c": + a = Center + case "r": + a = Right + case "bl": + a = BottomLeft + case "bc": + a = BottomCenter + case "br": + a = BottomRight + case "full": + a = Full + default: + return a, errors.Errorf("pdfcpu: unknown position anchor: %s", s) + } + return a, nil +} + +func parsePositionAnchorImp(s string, imp *Import) error { + a, err := parsePositionAnchor(s) + if err != nil { + return err + } + imp.Pos = a + return nil +} + +func parsePositionOffsetImp(s string, imp *Import) error { + + d := strings.Split(s, " ") + if len(d) != 2 { + return errors.Errorf("pdfcpu: illegal position offset string: need 2 numeric values, %s\n", s) + } + + f, err := strconv.ParseFloat(d[0], 64) + if err != nil { + return err + } + imp.Dx = int(toUserSpace(f, imp.InpUnit)) + + f, err = strconv.ParseFloat(d[1], 64) + if err != nil { + return err + } + imp.Dy = int(toUserSpace(f, imp.InpUnit)) + + return nil +} + +func parseScaleFactorImp(s string, imp *Import) (err error) { + imp.Scale, imp.ScaleAbs, err = parseScaleFactor(s) + return err +} + +func parseDPI(s string, imp *Import) (err error) { + imp.DPI, err = strconv.Atoi(s) + return err +} + +// ParseImportDetails parses an Import command string into an internal structure. +func ParseImportDetails(s string, u DisplayUnit) (*Import, error) { + + if s == "" { + return nil, nil + } + + imp := DefaultImportConfig() + imp.InpUnit = u + + ss := strings.Split(s, ",") + + for _, s := range ss { + + ss1 := strings.Split(s, ":") + if len(ss1) != 2 { + return nil, errors.New("pdfcpu: Invalid import configuration string. Please consult pdfcpu help import") + } + + paramPrefix := strings.TrimSpace(ss1[0]) + paramValueStr := strings.TrimSpace(ss1[1]) + + if err := impParamMap.Handle(paramPrefix, paramValueStr, imp); err != nil { + return nil, err + } + } + + return imp, nil +} + +// AppendPageTree appends a pagetree d1 to page tree d2. +func AppendPageTree(d1 *IndirectRef, countd1 int, d2 Dict) error { + a := d2.ArrayEntry("Kids") + a = append(a, *d1) + d2.Update("Kids", a) + return d2.IncrementBy("Count", countd1) +} + +func lowerLeftCorner(vpw, vph, bbw, bbh float64, a anchor) types.Point { + + var p types.Point + + switch a { + + case TopLeft: + p.X = 0 + p.Y = vph - bbh + + case TopCenter: + p.X = vpw/2 - bbw/2 + p.Y = vph - bbh + + case TopRight: + p.X = vpw - bbw + p.Y = vph - bbh + + case Left: + p.X = 0 + p.Y = vph/2 - bbh/2 + + case Center: + p.X = vpw/2 - bbw/2 + p.Y = vph/2 - bbh/2 + + case Right: + p.X = vpw - bbw + p.Y = vph/2 - bbh/2 + + case BottomLeft: + p.X = 0 + p.Y = 0 + + case BottomCenter: + p.X = vpw/2 - bbw/2 + p.Y = 0 + + case BottomRight: + p.X = vpw - bbw + p.Y = 0 + } + + return p +} + +func importImagePDFBytes(wr io.Writer, pageDim *Dim, imgWidth, imgHeight float64, imp *Import) { + + vpw := float64(pageDim.Width) + vph := float64(pageDim.Height) + + if imp.Pos == Full { + // The bounding box equals the page dimensions. + bb := types.NewRectangle(0, 0, vpw, vph) + bb.UR.X = bb.Width() + bb.UR.Y = bb.UR.X / bb.AspectRatio() + fmt.Fprintf(wr, "q %f 0 0 %f 0 0 cm /Im0 Do Q", bb.Width(), bb.Height()) + return + } + + if imp.DPI > 0 { + // NOTE: We could also set "UserUnit" in the page dict. + imgWidth *= float64(72) / float64(imp.DPI) + imgHeight *= float64(72) / float64(imp.DPI) + } + + bb := types.NewRectangle(0, 0, imgWidth, imgHeight) + ar := bb.AspectRatio() + + if imp.ScaleAbs { + bb.UR.X = imp.Scale * bb.Width() + bb.UR.Y = bb.UR.X / ar + } else { + if ar >= 1 { + bb.UR.X = imp.Scale * vpw + bb.UR.Y = bb.UR.X / ar + } else { + bb.UR.Y = imp.Scale * vph + bb.UR.X = bb.UR.Y * ar + } + } + + m := identMatrix + + // Scale + m[0][0] = bb.Width() + m[1][1] = bb.Height() + + // Translate + ll := lowerLeftCorner(vpw, vph, bb.Width(), bb.Height(), imp.Pos) + m[2][0] = ll.X + float64(imp.Dx) + m[2][1] = ll.Y + float64(imp.Dy) + + fmt.Fprintf(wr, "q %.2f %.2f %.2f %.2f %.2f %.2f cm /Im0 Do Q", + m[0][0], m[0][1], m[1][0], m[1][1], m[2][0], m[2][1]) +} + +// NewPageForImage creates a new page dict in xRefTable for given image reader r. +func NewPageForImage(xRefTable *XRefTable, r io.Reader, parentIndRef *IndirectRef, imp *Import) (*IndirectRef, error) { + + // create image dict. + imgIndRef, w, h, err := createImageResource(xRefTable, r) + if err != nil { + return nil, err + } + + // create resource dict for XObject. + d := Dict( + map[string]Object{ + "ProcSet": NewNameArray("PDF", "Text", "ImageB", "ImageC", "ImageI"), + "XObject": Dict(map[string]Object{"Im0": *imgIndRef}), + }, + ) + + resIndRef, err := xRefTable.IndRefForNewObject(d) + if err != nil { + return nil, err + } + + dim := &Dim{float64(w), float64(h)} + if imp.Pos != Full { + dim = imp.PageDim + } + // mediabox = physical page dimensions + mediaBox := RectForDim(dim.Width, dim.Height) + + var buf bytes.Buffer + importImagePDFBytes(&buf, dim, float64(w), float64(h), imp) + sd, _ := xRefTable.NewStreamDictForBuf(buf.Bytes()) + if err = sd.Encode(); err != nil { + return nil, err + } + + contentsIndRef, err := xRefTable.IndRefForNewObject(*sd) + if err != nil { + return nil, err + } + + pageDict := Dict( + map[string]Object{ + "Type": Name("Page"), + "Parent": *parentIndRef, + "MediaBox": mediaBox.Array(), + "Resources": *resIndRef, + "Contents": *contentsIndRef, + }, + ) + + return xRefTable.IndRefForNewObject(pageDict) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/info.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/info.go new file mode 100644 index 0000000..a768563 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/info.go @@ -0,0 +1,380 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + "strings" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" +) + +func csvSafeString(s string) string { + return strings.Replace(s, ";", ",", -1) +} + +// handleInfoDict extracts relevant infoDict fields into the context. +func (ctx *Context) handleInfoDict(d Dict) (err error) { + + for key, value := range d { + + switch key { + + case "Title": + log.Write.Println("found Title") + + case "Author": + log.Write.Println("found Author") + // Record for stats. + ctx.Author, err = ctx.DereferenceText(value) + if err != nil { + return err + } + ctx.Author = csvSafeString(ctx.Author) + + case "Subject": + log.Write.Println("found Subject") + + case "Keywords": + log.Write.Println("found Keywords") + + case "Creator": + log.Write.Println("found Creator") + // Record for stats. + ctx.Creator, err = ctx.DereferenceText(value) + if err != nil { + return err + } + ctx.Creator = csvSafeString(ctx.Creator) + + case "Producer", "CreationDate", "ModDate": + // pdfcpu will modify these as direct dict entries. + log.Write.Printf("found %s", key) + if indRef, ok := value.(IndirectRef); ok { + // Get rid of these extra objects. + ctx.Optimize.DuplicateInfoObjects[int(indRef.ObjectNumber)] = true + } + + case "Trapped": + log.Write.Println("found Trapped") + + default: + log.Write.Printf("handleInfoDict: found out of spec entry %s %v\n", key, value) + + } + } + + return nil +} + +func (ctx *Context) ensureInfoDict() error { + + // => 14.3.3 Document Information Dictionary + + // Optional: + // Title - + // Author - + // Subject - + // Keywords - + // Creator - + // Producer modified by pdfcpu + // CreationDate modified by pdfcpu + // ModDate modified by pdfcpu + // Trapped - + + now := DateString(time.Now()) + + v := "pdfcpu " + VersionStr + + if ctx.Info == nil { + + d := NewDict() + d.InsertString("Producer", v) + d.InsertString("CreationDate", now) + d.InsertString("ModDate", now) + + ir, err := ctx.IndRefForNewObject(d) + if err != nil { + return err + } + + ctx.Info = ir + + return nil + } + + d, err := ctx.DereferenceDict(*ctx.Info) + if err != nil || d == nil { + return err + } + + if err = ctx.handleInfoDict(d); err != nil { + return err + } + + d.Update("CreationDate", StringLiteral(now)) + d.Update("ModDate", StringLiteral(now)) + d.Update("Producer", StringLiteral(v)) + + return nil +} + +// Write the document info object for this PDF file. +func (ctx *Context) writeDocumentInfoDict() error { + + log.Write.Printf("*** writeDocumentInfoDict begin: offset=%d ***\n", ctx.Write.Offset) + + // Note: The document info object is optional but pdfcpu ensures one. + + if ctx.Info == nil { + log.Write.Printf("writeDocumentInfoObject end: No info object present, offset=%d\n", ctx.Write.Offset) + return nil + } + + log.Write.Printf("writeDocumentInfoObject: %s\n", *ctx.Info) + + o := *ctx.Info + + d, err := ctx.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + _, _, err = writeDeepObject(ctx, o) + if err != nil { + return err + } + + log.Write.Printf("*** writeDocumentInfoDict end: offset=%d ***\n", ctx.Write.Offset) + + return nil +} + +func appendEqualMediaAndCropBoxInfo(ss *[]string, pb PageBoundaries, unit string, currUnit DisplayUnit) { + mb := pb.MediaBox() + tb := pb.TrimBox() + bb := pb.BleedBox() + ab := pb.ArtBox() + s := " = CropBox" + + if tb == nil || tb.equals(*mb) { + s += ", TrimBox" + } + if bb == nil || bb.equals(*mb) { + s += ", BleedBox" + } + if ab == nil || ab.equals(*mb) { + s += ", ArtBox" + } + + *ss = append(*ss, fmt.Sprintf(" MediaBox (%s) %v %s", unit, mb.Format(currUnit), s)) + + if tb != nil && !tb.equals(*mb) { + *ss = append(*ss, fmt.Sprintf(" TrimBox (%s) %v", unit, tb.Format(currUnit))) + } + if bb != nil && !bb.equals(*mb) { + *ss = append(*ss, fmt.Sprintf(" BleedBox (%s) %v", unit, bb.Format(currUnit))) + } + if ab != nil && !ab.equals(*mb) { + *ss = append(*ss, fmt.Sprintf(" ArtBox (%s) %v", unit, ab.Format(currUnit))) + } +} + +func trimBleedArtBoxString(cb, tb, bb, ab *Rectangle) string { + s := "" + if tb == nil || tb.equals(*cb) { + s += "= TrimBox" + } + if bb == nil || bb.equals(*cb) { + if len(s) == 0 { + s += "= " + } else { + s += ", " + } + s += "BleedBox" + } + if ab == nil || ab.equals(*cb) { + if len(s) == 0 { + s += "= " + } else { + s += ", " + } + s += "ArtBox" + } + return s +} + +func appendNotEqualMediaAndCropBoxInfo(ss *[]string, pb PageBoundaries, unit string, currUnit DisplayUnit) { + mb := pb.MediaBox() + cb := pb.CropBox() + tb := pb.TrimBox() + bb := pb.BleedBox() + ab := pb.ArtBox() + + s := trimBleedArtBoxString(cb, tb, bb, ab) + *ss = append(*ss, fmt.Sprintf(" CropBox (%s) %v %s", unit, cb.Format(currUnit), s)) + + if tb != nil && !tb.equals(*mb) && !tb.equals(*cb) { + *ss = append(*ss, fmt.Sprintf(" TrimBox (%s) %v", unit, tb.Format(currUnit))) + } + if bb != nil && !bb.equals(*mb) && !bb.equals(*cb) { + *ss = append(*ss, fmt.Sprintf(" BleedBox (%s) %v", unit, bb.Format(currUnit))) + } + if ab != nil && !ab.equals(*mb) && !ab.equals(*cb) { + *ss = append(*ss, fmt.Sprintf(" ArtBox (%s) %v", unit, ab.Format(currUnit))) + } +} + +func appendPageBoxesInfo(ss *[]string, pb PageBoundaries, unit string, currUnit DisplayUnit, i int) { + *ss = append(*ss, fmt.Sprintf("Page %d:", i+1)) + mb := pb.MediaBox() + cb := pb.CropBox() + if cb == nil || mb.equals(*cb) { + appendEqualMediaAndCropBoxInfo(ss, pb, unit, currUnit) + return + } + appendNotEqualMediaAndCropBoxInfo(ss, pb, unit, currUnit) +} + +func (ctx *Context) pageInfo(selectedPages IntSet) ([]string, error) { + unit := ctx.unit() + if len(selectedPages) > 0 { + // TODO ctx.PageBoundaries(selectedPages) + pbs, err := ctx.PageBoundaries() + if err != nil { + return nil, err + } + ss := []string{} + for i, pb := range pbs { + if _, found := selectedPages[i+1]; !found { + continue + } + appendPageBoxesInfo(&ss, pb, unit, ctx.Unit, i) + } + return ss, nil + } + + pd, err := ctx.PageDims() + if err != nil { + return nil, err + } + + m := map[Dim]bool{} + for _, d := range pd { + m[d] = true + } + + ss := []string{} + s := "Page size:" + for d := range m { + dc := ctx.convertToUnit(d) + ss = append(ss, fmt.Sprintf("%21s %.2f x %.2f %s", s, dc.Width, dc.Height, unit)) + s = "" + } + + return ss, nil +} + +// InfoDigest returns info about ctx. +func (ctx *Context) InfoDigest(selectedPages IntSet) ([]string, error) { + var separator = "............................................" + var ss []string + v := ctx.HeaderVersion + if ctx.RootVersion != nil { + v = ctx.RootVersion + } + ss = append(ss, fmt.Sprintf("%20s: %s", "PDF version", v)) + ss = append(ss, fmt.Sprintf("%20s: %d", "Page count", ctx.PageCount)) + + pi, err := ctx.pageInfo(selectedPages) + if err != nil { + return nil, err + } + ss = append(ss, pi...) + + ss = append(ss, fmt.Sprintf(separator)) + ss = append(ss, fmt.Sprintf("%20s: %s", "Title", ctx.Title)) + ss = append(ss, fmt.Sprintf("%20s: %s", "Author", ctx.Author)) + ss = append(ss, fmt.Sprintf("%20s: %s", "Subject", ctx.Subject)) + ss = append(ss, fmt.Sprintf("%20s: %s", "PDF Producer", ctx.Producer)) + ss = append(ss, fmt.Sprintf("%20s: %s", "Content creator", ctx.Creator)) + ss = append(ss, fmt.Sprintf("%20s: %s", "Creation date", ctx.CreationDate)) + ss = append(ss, fmt.Sprintf("%20s: %s", "Modification date", ctx.ModDate)) + + if err := ctx.addKeywordsToInfoDigest(&ss); err != nil { + return nil, err + } + + if err := ctx.addPropertiesToInfoDigest(&ss); err != nil { + return nil, err + } + + ss = append(ss, fmt.Sprintf(separator)) + + s := "No" + if ctx.Tagged { + s = "Yes" + } + ss = append(ss, fmt.Sprintf(" Tagged: %s", s)) + + s = "No" + if ctx.Read.Hybrid { + s = "Yes" + } + ss = append(ss, fmt.Sprintf(" Hybrid: %s", s)) + + s = "No" + if ctx.Read.Linearized { + s = "Yes" + } + ss = append(ss, fmt.Sprintf(" Linearized: %s", s)) + + s = "No" + if ctx.Read.UsingXRefStreams { + s = "Yes" + } + ss = append(ss, fmt.Sprintf(" Using XRef streams: %s", s)) + + s = "No" + if ctx.Read.UsingObjectStreams { + s = "Yes" + } + ss = append(ss, fmt.Sprintf("Using object streams: %s", s)) + + s = "No" + if ctx.Watermarked { + s = "Yes" + } + ss = append(ss, fmt.Sprintf(" Watermarked: %s", s)) + + ss = append(ss, fmt.Sprintf(separator)) + + s = "No" + if ctx.Encrypt != nil { + s = "Yes" + } + ss = append(ss, fmt.Sprintf("%20s: %s", "Encrypted", s)) + + ctx.addPermissionsToInfoDigest(&ss) + + if err := ctx.addAttachmentsToInfoDigest(&ss); err != nil { + return nil, err + } + + return ss, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/keywords.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/keywords.go new file mode 100644 index 0000000..a0bd964 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/keywords.go @@ -0,0 +1,103 @@ +/* +Copyright 2020 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "strings" +) + +// KeywordsList returns a list of keywords as recorded in the document info dict. +func KeywordsList(xRefTable *XRefTable) ([]string, error) { + ss := strings.FieldsFunc(xRefTable.Keywords, func(c rune) bool { return c == ',' || c == ';' || c == '\r' }) + for i, s := range ss { + ss[i] = strings.TrimSpace(s) + } + return ss, nil +} + +// KeywordsAdd adds keywords to the document info dict. +// Returns true if at least one keyword was added. +func KeywordsAdd(xRefTable *XRefTable, keywords []string) error { + + list, err := KeywordsList(xRefTable) + if err != nil { + return err + } + + for _, s := range keywords { + if !MemberOf(s, list) { + xRefTable.Keywords += ", " + UTF8ToCP1252(s) + } + } + + d, err := xRefTable.DereferenceDict(*xRefTable.Info) + if err != nil || d == nil { + return err + } + + d["Keywords"] = StringLiteral(xRefTable.Keywords) + + return nil +} + +// KeywordsRemove deletes keywords from the document info dict. +// Returns true if at least one keyword was removed. +func KeywordsRemove(xRefTable *XRefTable, keywords []string) (bool, error) { + // TODO Handle missing info dict. + d, err := xRefTable.DereferenceDict(*xRefTable.Info) + if err != nil || d == nil { + return false, err + } + + if len(keywords) == 0 { + // Remove all keywords. + delete(d, "Keywords") + return true, nil + } + + kw := make([]string, len(keywords)) + for i, s := range keywords { + kw[i] = UTF8ToCP1252(s) + } + + // Distil document keywords. + ss := strings.FieldsFunc(xRefTable.Keywords, func(c rune) bool { return c == ',' || c == ';' || c == '\r' }) + + xRefTable.Keywords = "" + var removed bool + first := true + + for _, s := range ss { + s = strings.TrimSpace(s) + if MemberOf(s, kw) { + removed = true + continue + } + if first { + xRefTable.Keywords = s + first = false + continue + } + xRefTable.Keywords += ", " + s + } + + if removed { + d["Keywords"] = StringLiteral(xRefTable.Keywords) + } + + return removed, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/merge.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/merge.go new file mode 100644 index 0000000..845b088 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/merge.go @@ -0,0 +1,330 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "github.com/pdfcpu/pdfcpu/pkg/log" +) + +func patchIndRef(ir *IndirectRef, lookup map[int]int) { + i := ir.ObjectNumber.Value() + ir.ObjectNumber = Integer(lookup[i]) +} + +func patchObject(o Object, lookup map[int]int) Object { + + log.Trace.Printf("patchObject before: %v\n", o) + + var ob Object + + switch obj := o.(type) { + + case IndirectRef: + patchIndRef(&obj, lookup) + ob = obj + + case Dict: + patchDict(obj, lookup) + ob = obj + + case StreamDict: + patchDict(obj.Dict, lookup) + ob = obj + + case ObjectStreamDict: + patchDict(obj.Dict, lookup) + ob = obj + + case XRefStreamDict: + patchDict(obj.Dict, lookup) + ob = obj + + case Array: + patchArray(obj, lookup) + ob = obj + + } + + log.Trace.Printf("patchObject end: %v\n", ob) + + return ob +} + +func patchDict(d Dict, lookup map[int]int) { + + log.Trace.Printf("patchDict before: %v\n", d) + + for k, obj := range d { + o := patchObject(obj, lookup) + if o != nil { + d[k] = o + } + } + + log.Trace.Printf("patchDict after: %v\n", d) +} + +func patchArray(a Array, lookup map[int]int) { + + log.Trace.Printf("patchArray begin: %v\n", a) + + for i, obj := range a { + o := patchObject(obj, lookup) + if o != nil { + a[i] = o + } + } + + log.Trace.Printf("patchArray end: %v\n", a) +} + +func objNrsIntSet(ctx *Context) IntSet { + + objNrs := IntSet{} + + for k := range ctx.Table { + if k == 0 { + // obj#0 is always the head of the freelist. + continue + } + objNrs[k] = true + } + + return objNrs +} + +func lookupTable(keys IntSet, i int) map[int]int { + + m := map[int]int{} + + for k := range keys { + m[k] = i + i++ + } + + return m +} + +// Patch an IntSet of objNrs using lookup. +func patchObjects(s IntSet, lookup map[int]int) IntSet { + + t := IntSet{} + + for k, v := range s { + if v { + t[lookup[k]] = v + } + } + + return t +} + +func patchSourceObjectNumbers(ctxSource, ctxDest *Context) { + + log.Debug.Printf("patchSourceObjectNumbers: ctxSource: xRefTableSize:%d trailer.Size:%d - %s\n", len(ctxSource.Table), *ctxSource.Size, ctxSource.Read.FileName) + log.Debug.Printf("patchSourceObjectNumbers: ctxDest: xRefTableSize:%d trailer.Size:%d - %s\n", len(ctxDest.Table), *ctxDest.Size, ctxDest.Read.FileName) + + // Patch source xref tables obj numbers which are essentially the keys. + //logInfoMerge.Printf("Source XRefTable before:\n%s\n", ctxSource) + + objNrs := objNrsIntSet(ctxSource) + + // Create lookup table for object numbers. + // The first number is the successor of the last number in ctxDest. + lookup := lookupTable(objNrs, *ctxDest.Size) + + // Patch pointer to root object + patchIndRef(ctxSource.Root, lookup) + + // Patch pointer to info object + if ctxSource.Info != nil { + patchIndRef(ctxSource.Info, lookup) + } + + // Patch free object zero + entry := ctxSource.Table[0] + off := int(*entry.Offset) + if off != 0 { + i := int64(lookup[off]) + entry.Offset = &i + } + + // Patch all indRefs for xref table entries. + for k := range objNrs { + + //logDebugMerge.Printf("patching obj #%d\n", k) + + entry := ctxSource.Table[k] + + if entry.Free { + log.Debug.Printf("patch free entry: old offset:%d\n", *entry.Offset) + off := int(*entry.Offset) + if off == 0 { + continue + } + i := int64(lookup[off]) + entry.Offset = &i + log.Debug.Printf("patch free entry: new offset:%d\n", *entry.Offset) + continue + } + + patchObject(entry.Object, lookup) + } + + // Patch xref entry object numbers. + m := make(map[int]*XRefTableEntry, *ctxSource.Size) + for k, v := range lookup { + m[v] = ctxSource.Table[k] + } + m[0] = ctxSource.Table[0] + ctxSource.Table = m + + // Patch DuplicateInfo object numbers. + ctxSource.Optimize.DuplicateInfoObjects = patchObjects(ctxSource.Optimize.DuplicateInfoObjects, lookup) + + // Patch Linearization object numbers. + ctxSource.LinearizationObjs = patchObjects(ctxSource.LinearizationObjs, lookup) + + // Patch XRefStream objects numbers. + ctxSource.Read.XRefStreams = patchObjects(ctxSource.Read.XRefStreams, lookup) + + // Patch object stream object numbers. + ctxSource.Read.ObjectStreams = patchObjects(ctxSource.Read.ObjectStreams, lookup) + + log.Debug.Printf("patchSourceObjectNumbers end") +} + +func appendSourcePageTreeToDestPageTree(ctxSource, ctxDest *Context) error { + + log.Debug.Println("appendSourcePageTreeToDestPageTree begin") + + indRefPageTreeRootDictSource, err := ctxSource.Pages() + if err != nil { + return err + } + + pageTreeRootDictSource, _ := ctxSource.XRefTable.DereferenceDict(*indRefPageTreeRootDictSource) + pageCountSource := pageTreeRootDictSource.IntEntry("Count") + + indRefPageTreeRootDictDest, err := ctxDest.Pages() + if err != nil { + return err + } + + pageTreeRootDictDest, _ := ctxDest.XRefTable.DereferenceDict(*indRefPageTreeRootDictDest) + pageCountDest := pageTreeRootDictDest.IntEntry("Count") + + a := pageTreeRootDictDest.ArrayEntry("Kids") + log.Debug.Printf("Kids before: %v\n", a) + + pageTreeRootDictSource.Insert("Parent", *indRefPageTreeRootDictDest) + + // The source page tree gets appended on to the dest page tree. + a = append(a, *indRefPageTreeRootDictSource) + log.Debug.Printf("Kids after: %v\n", a) + + pageTreeRootDictDest.Update("Count", Integer(*pageCountDest+*pageCountSource)) + pageTreeRootDictDest.Update("Kids", a) + + ctxDest.PageCount += ctxSource.PageCount + + log.Debug.Println("appendSourcePageTreeToDestPageTree end") + + return nil +} + +func appendSourceObjectsToDest(ctxSource, ctxDest *Context) { + + log.Debug.Println("appendSourceObjectsToDest begin") + + for objNr, entry := range ctxSource.Table { + + // Do not copy free list head. + if objNr == 0 { + continue + } + + log.Debug.Printf("adding obj %d from src to dest\n", objNr) + + ctxDest.Table[objNr] = entry + + *ctxDest.Size++ + + } + + log.Debug.Println("appendSourceObjectsToDest end") +} + +// merge two disjunct IntSets +func mergeIntSets(src, dest IntSet) { + for k := range src { + dest[k] = true + } +} + +func mergeDuplicateObjNumberIntSets(ctxSource, ctxDest *Context) { + + log.Debug.Println("mergeDuplicateObjNumberIntSets begin") + + mergeIntSets(ctxSource.Optimize.DuplicateInfoObjects, ctxDest.Optimize.DuplicateInfoObjects) + mergeIntSets(ctxSource.LinearizationObjs, ctxDest.LinearizationObjs) + mergeIntSets(ctxSource.Read.XRefStreams, ctxDest.Read.XRefStreams) + mergeIntSets(ctxSource.Read.ObjectStreams, ctxDest.Read.ObjectStreams) + + log.Debug.Println("mergeDuplicateObjNumberIntSets end") +} + +// MergeXRefTables merges Context ctxSource into ctxDest by appending its page tree. +func MergeXRefTables(ctxSource, ctxDest *Context) (err error) { + + // Sweep over ctxSource cross ref table and ensure valid object numbers in ctxDest's space. + patchSourceObjectNumbers(ctxSource, ctxDest) + + // Append ctxSource pageTree to ctxDest pageTree. + log.Debug.Println("appendSourcePageTreeToDestPageTree") + err = appendSourcePageTreeToDestPageTree(ctxSource, ctxDest) + if err != nil { + return err + } + + // Append ctxSource objects to ctxDest + log.Debug.Println("appendSourceObjectsToDest") + appendSourceObjectsToDest(ctxSource, ctxDest) + + // Mark source's root object as free. + err = ctxDest.DeleteObject(int(ctxSource.Root.ObjectNumber)) + if err != nil { + return + } + + // Mark source's info object as free. + // Note: Any indRefs this info object depends on are missed. + if ctxSource.Info != nil { + err = ctxDest.DeleteObject(int(ctxSource.Info.ObjectNumber)) + if err != nil { + return + } + } + + // Merge all IntSets containing redundant object numbers. + log.Debug.Println("mergeDuplicateObjNumberIntSets") + mergeDuplicateObjNumberIntSets(ctxSource, ctxDest) + + log.Info.Printf("Dest XRefTable after merge:\n%s\n", ctxDest) + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/nameTree.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/nameTree.go new file mode 100644 index 0000000..facc4c4 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/nameTree.go @@ -0,0 +1,487 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/log" +) + +const maxEntries = 3 + +// Node is an opinionated implementation of the PDF name tree. +// pdfcpu caches all name trees found in the PDF catalog with this data structure. +// The PDF spec does not impose any rules regarding a strategy for the creation of nodes. +// A binary tree was chosen where each leaf node has a limited number of entries (maxEntries). +// Once maxEntries has been reached a leaf node turns into an intermediary node with two kids, +// which are leaf nodes each of them holding half of the sorted entries of the original leaf node. +type Node struct { + Kids []*Node // Mirror of the name tree's Kids array, an array of indirect references. + Names []entry // Mirror of the name tree's Names array. + Kmin, Kmax string // Mirror of the name tree's Limit array[Kmin,Kmax]. + D Dict // The PDF dict representing this name tree node. +} + +// entry is a key value pair. +type entry struct { + k string + v Object +} + +func (n Node) leaf() bool { + return n.Kids == nil +} + +func (n Node) withinLimits(k string) bool { + + if n.leaf() { + return n.Kmin <= k && k <= n.Kmax + } + + for _, v := range n.Kids { + if v.withinLimits(k) { + return true + } + } + + return false +} + +// Value returns the value for given key +func (n Node) Value(k string) (Object, bool) { + + if n.leaf() { + + if k < n.Kmin || n.Kmax < k { + return nil, false + } + + // names are sorted by key. + for _, v := range n.Names { + + if v.k < k { + continue + } + + if v.k == k { + return v.v, true + } + + return nil, false + } + + } + + // kids are sorted by key ranges. + for _, v := range n.Kids { + if v.withinLimits(k) { + return v.Value(k) + } + } + + return nil, false +} + +// AddToLeaf adds an entry to a leaf. +func (n *Node) AddToLeaf(k string, v Object) { + + if n.Names == nil { + n.Names = make([]entry, 0, maxEntries) + } + + n.Names = append(n.Names, entry{k, v}) +} + +// HandleLeaf processes a leaf node. +func (n *Node) HandleLeaf(xRefTable *XRefTable, k string, v Object) error { + // A leaf node contains up to maxEntries names. + // Any number of entries greater than maxEntries will be delegated to kid nodes. + + if len(n.Names) == 0 { + n.Names = append(n.Names, entry{k, v}) + n.Kmin, n.Kmax = k, k + log.Debug.Printf("first key=%s\n", k) + return nil + } + + log.Debug.Printf("kmin=%s kmax=%s\n", n.Kmin, n.Kmax) + + if k < n.Kmin { + // Insert (k,v) at the beginning. + log.Debug.Printf("Insert k:%s at beginning\n", k) + n.Kmin = k + n.Names = append(n.Names, entry{}) + copy(n.Names[1:], n.Names[0:]) + n.Names[0] = entry{k, v} + } else if k > n.Kmax { + // Insert (k,v) at the end. + log.Debug.Printf("Insert k:%s at end\n", k) + n.Kmax = k + n.Names = append(n.Names, entry{k, v}) + } else { + // Insert (k,v) somewhere in the middle. + log.Debug.Printf("Insert k:%s in the middle\n", k) + for i, e := range n.Names { + + if e.k < k { + continue + } + + // Adding an already existing key updates its value. + if e.k == k { + + // Free up all objs referred to by old values. + if xRefTable != nil { + err := xRefTable.DeleteObjectGraph(n.Names[i].v) + if err != nil { + return err + } + } + + n.Names[i].v = v + break + } + + // Insert entry(k,v) at i + n.Names = append(n.Names, entry{}) + copy(n.Names[i+1:], n.Names[i:]) // ? + n.Names[i] = entry{k, v} + break + } + } + + // if len was already > maxEntries we know we are dealing with somebody elses name tree. + // In that case we do not know the branching strategy and therefore just add to Names and do not create kids. + // If len is within maxEntries we do not create kids either way. + if len(n.Names) != maxEntries+1 { + return nil + } + + // turn leaf into intermediate node with 2 kids/leafs (binary tree) + c := maxEntries + 1 + k1 := &Node{Names: make([]entry, c/2, maxEntries)} + copy(k1.Names, n.Names[:c/2]) + k1.Kmin = n.Names[0].k + k1.Kmax = n.Names[c/2-1].k + + k2 := &Node{Names: make([]entry, len(n.Names)-c/2, maxEntries)} + copy(k2.Names, n.Names[c/2:]) + k2.Kmin = n.Names[c/2].k + k2.Kmax = n.Names[c-1].k + + n.Kids = []*Node{k1, k2} + n.Names = nil + + return nil +} + +// Add adds an entry to a name tree. +func (n *Node) Add(xRefTable *XRefTable, k string, v Object) error { + + // The values associated with the keys may be objects of any type. + // Stream objects shall be specified by indirect object references. + // Dictionary, array, and string objects should be specified by indirect object references. + // Other PDF objects (nulls, numbers, booleans, and names) should be specified as direct objects. + + if n.Names == nil { + n.Names = make([]entry, 0, maxEntries) + } + + if n.leaf() { + return n.HandleLeaf(xRefTable, k, v) + } + + if k < n.Kmin { + n.Kmin = k + } else if k > n.Kmax { + n.Kmax = k + } + + // For intermediary nodes we delegate to the corresponding subtree. + for _, a := range n.Kids { + if k < a.Kmin || a.withinLimits(k) { + if !a.leaf() { + if k < a.Kmin { + a.Kmin = k + } else if k > a.Kmax { + a.Kmax = k + } + } + return a.Add(xRefTable, k, v) + } + } + + // Insert k into last (right most) subtree. + last := n.Kids[len(n.Kids)-1] + if !last.leaf() { + if k < last.Kmin { + last.Kmin = k + } else if k > last.Kmax { + last.Kmax = k + } + } + return last.Add(xRefTable, k, v) +} + +func (n *Node) removeFromNames(xRefTable *XRefTable, k string) (ok bool, err error) { + + for i, v := range n.Names { + + if v.k < k { + continue + } + + if v.k == k { + + if xRefTable != nil { + // Remove object graph of value. + log.Debug.Println("removeFromNames: deleting object graph of v") + err := xRefTable.DeleteObjectGraph(v.v) + if err != nil { + return false, err + } + } + + n.Names = append(n.Names[:i], n.Names[i+1:]...) + return true, nil + } + + } + + return false, nil +} + +func (n *Node) removeFromLeaf(xRefTable *XRefTable, k string) (empty, ok bool, err error) { + + if k < n.Kmin || n.Kmax < k { + return false, false, nil + } + + // kmin < k < kmax + + // If sole entry gets deleted, remove this node from parent. + if len(n.Names) == 1 { + if xRefTable != nil { + // Remove object graph of value. + log.Debug.Println("removeFromLeaf: deleting object graph of v") + err := xRefTable.DeleteObjectGraph(n.Names[0].v) + if err != nil { + return false, false, err + } + } + n.Kmin, n.Kmax = "", "" + n.Names = nil + return true, true, nil + } + + if k == n.Kmin { + + if xRefTable != nil { + // Remove object graph of value. + log.Debug.Println("removeFromLeaf: deleting object graph of v") + err := xRefTable.DeleteObjectGraph(n.Names[0].v) + if err != nil { + return false, false, err + } + } + + n.Names = n.Names[1:] + n.Kmin = n.Names[0].k + return false, true, nil + } + + if k == n.Kmax { + + if xRefTable != nil { + // Remove object graph of value. + log.Debug.Println("removeFromLeaf: deleting object graph of v") + err := xRefTable.DeleteObjectGraph(n.Names[len(n.Names)-1].v) + if err != nil { + return false, false, err + } + } + + n.Names = n.Names[:len(n.Names)-1] + n.Kmax = n.Names[len(n.Names)-1].k + return false, true, nil + } + + ok, err = n.removeFromNames(xRefTable, k) + if err != nil { + return false, false, err + } + + return false, ok, nil +} + +func (n *Node) removeFromKids(xRefTable *XRefTable, k string) (ok bool, err error) { + + // Locate the kid to recurse into, then remove k from that subtree. + for i, kid := range n.Kids { + + if !kid.withinLimits(k) { + continue + } + + empty, ok, err := kid.Remove(xRefTable, k) + if err != nil { + return false, err + } + if !ok { + return false, nil + } + + if empty { + + // This kid is now empty and needs to be removed. + + if xRefTable != nil { + err = xRefTable.deleteObject(kid.D) + if err != nil { + return false, err + } + } + + if i == 0 { + // Remove first kid. + log.Debug.Println("removeFromKids: remove first kid.") + n.Kids = n.Kids[1:] + } else if i == len(n.Kids)-1 { + log.Debug.Println("removeFromKids: remove last kid.") + // Remove last kid. + n.Kids = n.Kids[:len(n.Kids)-1] + } else { + // Remove kid from the middle. + log.Debug.Println("removeFromKids: remove kid form the middle.") + n.Kids = append(n.Kids[:i], n.Kids[i+1:]...) + } + + if len(n.Kids) == 1 { + + // If only one kid remains we can merge it with its parent. + // By doing this we get rid of a redundant intermediary node. + log.Debug.Println("removeFromKids: only 1 kid") + + if xRefTable != nil { + err = xRefTable.deleteObject(n.D) + if err != nil { + return false, err + } + } + + *n = *n.Kids[0] + + log.Debug.Printf("removeFromKids: new n = %s\n", n) + + return true, nil + } + + } + + // Update kMin, kMax for n. + n.Kmin = n.Kids[0].Kmin + n.Kmax = n.Kids[len(n.Kids)-1].Kmax + + return true, nil + } + + return false, nil +} + +// Remove removes an entry from a name tree. +// empty returns true if this node is an empty leaf node after removal. +// ok returns true if removal was successful. +func (n *Node) Remove(xRefTable *XRefTable, k string) (empty, ok bool, err error) { + + if n.leaf() { + return n.removeFromLeaf(xRefTable, k) + } + + ok, err = n.removeFromKids(xRefTable, k) + if err != nil { + return false, false, err + } + + return false, ok, nil + +} + +// Process traverses the nametree applying a handler to each entry (key-value pair). +func (n Node) Process(xRefTable *XRefTable, handler func(*XRefTable, string, Object) error) error { + + if !n.leaf() { + for _, v := range n.Kids { + err := v.Process(xRefTable, handler) + if err != nil { + return err + } + } + return nil + } + + for _, n := range n.Names { + err := handler(xRefTable, n.k, n.v) + if err != nil { + return err + } + } + + return nil +} + +// KeyList returns a sorted list of all keys. +func (n Node) KeyList() ([]string, error) { + + list := []string{} + + keys := func(xRefTable *XRefTable, k string, v Object) error { + list = append(list, k) + return nil + } + + err := n.Process(nil, keys) + if err != nil { + return nil, err + } + + return list, nil + +} + +func (n Node) String() string { + + a := []string{} + + if n.leaf() { + a = append(a, "[") + for _, n := range n.Names { + a = append(a, fmt.Sprintf("(%s,%s)", n.k, n.v)) + } + a = append(a, fmt.Sprintf("{%s,%s}]", n.Kmin, n.Kmax)) + return strings.Join(a, "") + } + + a = append(a, fmt.Sprintf("{%s,%s}", n.Kmin, n.Kmax)) + + for _, v := range n.Kids { + a = append(a, v.String()) + } + + return strings.Join(a, ",") +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/nup.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/nup.go new file mode 100644 index 0000000..6133bdd --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/nup.go @@ -0,0 +1,845 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bytes" + "fmt" + "io" + "math" + "os" + "sort" + "strconv" + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/filter" + "github.com/pkg/errors" +) + +var ( + errInvalidGridID = errors.New("pdfcpu: nup: n: one of 2, 3, 4, 6, 8, 9, 12, 16") + errInvalidGridDims = errors.New("pdfcpu: grid: dimensions: m >= 0, n >= 0") + errInvalidNUpConfig = errors.New("pdfcpu: nup: invalid configuration string. Please consult pdfcpu help nup") + errInvalidGridConfig = errors.New("pdfcpu: nup: invalid configuration string. Please consult pdfcpu help grid") +) + +var ( + nUpValues = []int{2, 3, 4, 6, 8, 9, 12, 16} + nUpDims = map[int]Dim{ + 2: {2, 1}, + 3: {3, 1}, + 4: {2, 2}, + 6: {3, 2}, + 8: {4, 2}, + 9: {3, 3}, + 12: {4, 3}, + 16: {4, 4}, + } +) + +type nUpParamMap map[string]func(string, *NUp) error + +var nupParamMap = nUpParamMap{ + "dimensions": parseDimensionsNUp, + "formsize": parsePageFormatNUp, + "papersize": parsePageFormatNUp, + "orientation": parseOrientation, + "border": parseElementBorder, + "margin": parseElementMargin, +} + +// Handle applies parameter completion and if successful +// parses the parameter values into import. +func (m nUpParamMap) Handle(paramPrefix, paramValueStr string, nup *NUp) error { + var param string + + // Completion support + for k := range m { + if !strings.HasPrefix(k, paramPrefix) { + continue + } + if len(param) > 0 { + return errors.Errorf("pdfcpu: ambiguous parameter prefix \"%s\"", paramPrefix) + } + param = k + } + + if param == "" { + return errors.Errorf("pdfcpu: ambiguous parameter prefix \"%s\"", paramPrefix) + } + + return m[param](paramValueStr, nup) +} + +// NUp represents the command details for the command "NUp". +type NUp struct { + PageDim *Dim // Page dimensions in display unit. + PageSize string // Paper size eg. A4L, A4P, A4(=default=A4P), see paperSize.go + UserDim bool // true if one of dimensions or paperSize provided overriding the default. + Orient orientation // One of rd(=default),dr,ld,dl + Grid *Dim // Intra page grid dimensions eg (2,2) + PageGrid bool // Create a mxn grid of pages for PDF inputfiles only (think "extra page n-Up"). + ImgInputFile bool // Process image or PDF input files. + Margin int // Cropbox for n-Up content. + Border bool // Draw bounding box. + InpUnit DisplayUnit // input display unit. +} + +// DefaultNUpConfig returns the default NUp configuration. +func DefaultNUpConfig() *NUp { + return &NUp{ + PageSize: "A4", + Orient: RightDown, + Margin: 3, + Border: true, + } +} + +func (nup NUp) String() string { + return fmt.Sprintf("N-Up conf: %s %s, orient=%s, grid=%s, pageGrid=%t, isImage=%t\n", + nup.PageSize, *nup.PageDim, nup.Orient, *nup.Grid, nup.PageGrid, nup.ImgInputFile) +} + +type orientation int + +func (o orientation) String() string { + switch o { + + case RightDown: + return "right down" + + case DownRight: + return "down right" + + case LeftDown: + return "left down" + + case DownLeft: + return "down left" + + } + + return "" +} + +// These are the defined anchors for relative positioning. +const ( + RightDown orientation = iota + DownRight + LeftDown + DownLeft +) + +func parsePageFormatNUp(s string, nup *NUp) (err error) { + if nup.UserDim { + return errors.New("pdfcpu: only one of formsize(papersize) or dimensions allowed") + } + nup.PageDim, nup.PageSize, err = parsePageFormat(s) + nup.UserDim = true + return err +} + +func parseDimensionsNUp(s string, nup *NUp) (err error) { + if nup.UserDim { + return errors.New("pdfcpu: only one of formsize(papersize) or dimensions allowed") + } + nup.PageDim, nup.PageSize, err = parsePageDim(s, nup.InpUnit) + nup.UserDim = true + return err +} + +func parseOrientation(s string, nup *NUp) error { + switch s { + case "rd": + nup.Orient = RightDown + case "dr": + nup.Orient = DownRight + case "ld": + nup.Orient = LeftDown + case "dl": + nup.Orient = DownLeft + default: + return errors.Errorf("pdfcpu: unknown nUp orientation: %s", s) + } + + return nil +} + +func parseElementBorder(s string, nup *NUp) error { + switch strings.ToLower(s) { + case "on", "true": + nup.Border = true + case "off", "false": + nup.Border = false + default: + return errors.New("pdfcpu: nUp border, please provide one of: on/off true/false") + } + + return nil +} + +func parseElementMargin(s string, nup *NUp) error { + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return err + } + + if f < 0 { + return errors.New("pdfcpu: nUp margin, Please provide a positive value") + } + + nup.Margin = int(toUserSpace(f, nup.InpUnit)) + + return nil +} + +// ParseNUpDetails parses a NUp command string into an internal structure. +func ParseNUpDetails(s string, nup *NUp) error { + err1 := errInvalidNUpConfig + if nup.PageGrid { + err1 = errInvalidGridConfig + } + + if s == "" { + return err1 + } + + ss := strings.Split(s, ",") + + for _, s := range ss { + + ss1 := strings.Split(s, ":") + if len(ss1) != 2 { + return err1 + } + + paramPrefix := strings.TrimSpace(ss1[0]) + paramValueStr := strings.TrimSpace(ss1[1]) + + if err := nupParamMap.Handle(paramPrefix, paramValueStr, nup); err != nil { + return err + } + } + + return nil +} + +// PDFNUpConfig returns an NUp configuration for Nup-ing PDF files. +func PDFNUpConfig(val int, desc string) (*NUp, error) { + nup := DefaultNUpConfig() + if desc != "" { + if err := ParseNUpDetails(desc, nup); err != nil { + return nil, err + } + } + return nup, ParseNUpValue(val, nup) +} + +// ImageNUpConfig returns an NUp configuration for Nup-ing image files. +func ImageNUpConfig(val int, desc string) (*NUp, error) { + nup, err := PDFNUpConfig(val, desc) + if err != nil { + return nil, err + } + nup.ImgInputFile = true + return nup, nil +} + +// PDFGridConfig returns a grid configuration for Nup-ing PDF files. +func PDFGridConfig(rows, cols int, desc string) (*NUp, error) { + nup := DefaultNUpConfig() + nup.PageGrid = true + if desc != "" { + if err := ParseNUpDetails(desc, nup); err != nil { + return nil, err + } + } + return nup, ParseNUpGridDefinition(rows, cols, nup) +} + +// ImageGridConfig returns a grid configuration for Nup-ing image files. +func ImageGridConfig(rows, cols int, desc string) (*NUp, error) { + nup, err := PDFGridConfig(rows, cols, desc) + if err != nil { + return nil, err + } + nup.ImgInputFile = true + return nup, nil +} + +// ParseNUpValue parses the NUp value into an internal structure. +func ParseNUpValue(n int, nUp *NUp) error { + if !IntMemberOf(n, nUpValues) { + return errInvalidGridID + } + + // The n-Up layout depends on the orientation of the chosen output paper size. + // This optional paper size may also be specified by dimensions in user unit. + // The default paper size is A4 or A4P (A4 in portrait mode) respectively. + var portrait bool + if nUp.PageDim == nil { + portrait = PaperSize[nUp.PageSize].Portrait() + } else { + portrait = RectForDim(nUp.PageDim.Width, nUp.PageDim.Height).Portrait() + } + + d := nUpDims[n] + if portrait { + d.Width, d.Height = d.Height, d.Width + } + + nUp.Grid = &d + + return nil +} + +// ParseNUpGridDefinition parses NUp grid dimensions into an internal structure. +func ParseNUpGridDefinition(rows, cols int, nUp *NUp) error { + m := cols + if m <= 0 { + return errInvalidGridDims + } + + n := rows + if m <= 0 { + return errInvalidGridDims + } + + nUp.Grid = &Dim{float64(m), float64(n)} + + return nil +} + +func rectsForGrid(nup *NUp) []*Rectangle { + cols := int(nup.Grid.Width) + rows := int(nup.Grid.Height) + + maxX := float64(nup.PageDim.Width) + maxY := float64(nup.PageDim.Height) + + gw := maxX / float64(cols) + gh := maxY / float64(rows) + + var llx, lly float64 + rr := []*Rectangle{} + + switch nup.Orient { + + case RightDown: + for i := rows - 1; i >= 0; i-- { + for j := 0; j < cols; j++ { + llx = float64(j) * gw + lly = float64(i) * gh + rr = append(rr, Rect(llx, lly, llx+gw, lly+gh)) + } + } + + case DownRight: + for i := 0; i < cols; i++ { + for j := rows - 1; j >= 0; j-- { + llx = float64(i) * gw + lly = float64(j) * gh + rr = append(rr, Rect(llx, lly, llx+gw, lly+gh)) + } + } + + case LeftDown: + for i := rows - 1; i >= 0; i-- { + for j := cols - 1; j >= 0; j-- { + llx = float64(j) * gw + lly = float64(i) * gh + rr = append(rr, Rect(llx, lly, llx+gw, lly+gh)) + } + } + + case DownLeft: + for i := cols - 1; i >= 0; i-- { + for j := rows - 1; j >= 0; j-- { + llx = float64(i) * gw + lly = float64(j) * gh + rr = append(rr, Rect(llx, lly, llx+gw, lly+gh)) + } + } + } + + return rr +} + +// Calculate the matrix for transforming rectangle r1 with lower left corner in the origin into rectangle r2. +func calcTransMatrixForRect(r1, r2 *Rectangle, image bool) matrix { + var ( + w, h float64 + dx, dy float64 + rot float64 + ) + + if r2.Landscape() && r1.Portrait() || r2.Portrait() && r1.Landscape() { + rot = 90 + r1.UR.X, r1.UR.Y = r1.UR.Y, r1.UR.X + } + + if r1.FitsWithin(r2) { + // Translate r1 into center of r2 w/o scaling up. + w = r1.Width() + h = r1.Height() + } else if r1.AspectRatio() <= r2.AspectRatio() { + // Scale down r1 height to fit into r2 height. + h = r2.Height() + w = r1.ScaledWidth(h) + } else { + // Scale down r1 width to fit into r2 width. + w = r2.Width() + h = r1.ScaledHeight(w) + } + + dx = r2.LL.X - r1.LL.X*w/r1.Width() + r2.Width()/2 - w/2 + dy = r2.LL.Y - r1.LL.Y*h/r1.Height() + r2.Height()/2 - h/2 + + if rot > 0 { + dx += w + if !image { + w /= r1.Width() + h /= r1.Height() + } + w, h = h, w + } else if !image { + w /= r1.Width() + h /= r1.Height() + } + + // Scale + m1 := identMatrix + m1[0][0] = w + m1[1][1] = h + + // Rotate + m2 := identMatrix + sin := math.Sin(float64(rot) * float64(degToRad)) + cos := math.Cos(float64(rot) * float64(degToRad)) + m2[0][0] = cos + m2[0][1] = sin + m2[1][0] = -sin + m2[1][1] = cos + + // Translate + m3 := identMatrix + m3[2][0] = dx + m3[2][1] = dy + + return m1.multiply(m2).multiply(m3) +} + +func nUpTilePDFBytes(wr io.Writer, r1, r2 *Rectangle, formResID string, nup *NUp) { + // Draw bounding box. + if nup.Border { + fmt.Fprintf(wr, "[]0 d 0.1 w %.2f %.2f m %.2f %.2f l %.2f %.2f l %.2f %.2f l s ", + r2.LL.X, r2.LL.Y, r2.UR.X, r2.LL.Y, r2.UR.X, r2.UR.Y, r2.LL.X, r2.UR.Y, + ) + } + + // Apply margin. + croppedRect := r2.CroppedCopy(float64(nup.Margin)) + + m := calcTransMatrixForRect(r1, croppedRect, nup.ImgInputFile) + + fmt.Fprintf(wr, "q %.2f %.2f %.2f %.2f %.2f %.2f cm /%s Do Q ", + m[0][0], m[0][1], m[1][0], m[1][1], m[2][0], m[2][1], formResID) +} + +func nUpImagePDFBytes(wr io.Writer, imgWidth, imgHeight int, nup *NUp, formResID string) { + for _, r := range rectsForGrid(nup) { + nUpTilePDFBytes(wr, RectForDim(float64(imgWidth), float64(imgHeight)), r, formResID, nup) + } +} + +func createNUpForm(xRefTable *XRefTable, imgIndRef *IndirectRef, w, h, i int) (*IndirectRef, error) { + imgResID := fmt.Sprintf("Im%d", i) + bb := RectForDim(float64(w), float64(h)) + + var b bytes.Buffer + fmt.Fprintf(&b, "/%s Do ", imgResID) + + d := Dict( + map[string]Object{ + "ProcSet": NewNameArray("PDF", "Text", "ImageB", "ImageC", "ImageI"), + "XObject": Dict(map[string]Object{imgResID: *imgIndRef}), + }, + ) + + ir, err := xRefTable.IndRefForNewObject(d) + if err != nil { + return nil, err + } + + sd := StreamDict{ + Dict: Dict( + map[string]Object{ + "Type": Name("XObject"), + "Subtype": Name("Form"), + "BBox": bb.Array(), + "Matrix": NewIntegerArray(1, 0, 0, 1, 0, 0), + "Resources": *ir, + }, + ), + Content: b.Bytes(), + FilterPipeline: []PDFFilter{{Name: filter.Flate, DecodeParms: nil}}, + } + + sd.InsertName("Filter", filter.Flate) + + if err = sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(sd) +} + +func createNUpFormForPDFResource(xRefTable *XRefTable, resDict *IndirectRef, content []byte, cropBox *Rectangle) (*IndirectRef, error) { + sd := StreamDict{ + Dict: Dict( + map[string]Object{ + "Type": Name("XObject"), + "Subtype": Name("Form"), + "BBox": cropBox.Array(), + "Matrix": NewIntegerArray(1, 0, 0, 1, 0, 0), + "Resources": *resDict, + }, + ), + Content: content, + FilterPipeline: []PDFFilter{{Name: filter.Flate, DecodeParms: nil}}, + } + + sd.InsertName("Filter", filter.Flate) + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(sd) +} + +// NewNUpPageForImage creates a new page dict in xRefTable for given image filename and n-up conf. +func NewNUpPageForImage(xRefTable *XRefTable, fileName string, parentIndRef *IndirectRef, nup *NUp) (*IndirectRef, error) { + f, err := os.Open(fileName) + if err != nil { + return nil, err + } + defer f.Close() + + // create image dict. + imgIndRef, w, h, err := createImageResource(xRefTable, f) + if err != nil { + return nil, err + } + + resID := 0 + + formIndRef, err := createNUpForm(xRefTable, imgIndRef, w, h, resID) + if err != nil { + return nil, err + } + + formResID := fmt.Sprintf("Fm%d", resID) + + resourceDict := Dict( + map[string]Object{ + "XObject": Dict(map[string]Object{formResID: *formIndRef}), + }, + ) + + resIndRef, err := xRefTable.IndRefForNewObject(resourceDict) + if err != nil { + return nil, err + } + + var buf bytes.Buffer + nUpImagePDFBytes(&buf, w, h, nup, formResID) + sd, _ := xRefTable.NewStreamDictForBuf(buf.Bytes()) + if err = sd.Encode(); err != nil { + return nil, err + } + + contentsIndRef, err := xRefTable.IndRefForNewObject(*sd) + if err != nil { + return nil, err + } + + // mediabox = physical page dimensions + dim := nup.PageDim + mediaBox := RectForDim(dim.Width, dim.Height) + + pageDict := Dict( + map[string]Object{ + "Type": Name("Page"), + "Parent": *parentIndRef, + "MediaBox": mediaBox.Array(), + "Resources": *resIndRef, + "Contents": *contentsIndRef, + }, + ) + + return xRefTable.IndRefForNewObject(pageDict) +} + +// NUpFromOneImage creates one page with instances of one image. +func NUpFromOneImage(ctx *Context, fileName string, nup *NUp, pagesDict Dict, pagesIndRef *IndirectRef) error { + indRef, err := NewNUpPageForImage(ctx.XRefTable, fileName, pagesIndRef, nup) + if err != nil { + return err + } + + if err = AppendPageTree(indRef, 1, pagesDict); err != nil { + return err + } + + ctx.PageCount++ + + return nil +} + +func wrapUpPage(ctx *Context, nup *NUp, d Dict, buf bytes.Buffer, pagesDict Dict, pagesIndRef *IndirectRef) error { + xRefTable := ctx.XRefTable + + resourceDict := Dict( + map[string]Object{ + "XObject": d, + }, + ) + + resIndRef, err := xRefTable.IndRefForNewObject(resourceDict) + if err != nil { + return err + } + + sd, _ := xRefTable.NewStreamDictForBuf(buf.Bytes()) + if err = sd.Encode(); err != nil { + return err + } + + contentsIndRef, err := xRefTable.IndRefForNewObject(*sd) + if err != nil { + return err + } + + // mediabox = physical page dimensions + dim := nup.PageDim + mediaBox := RectForDim(dim.Width, dim.Height) + + pageDict := Dict( + map[string]Object{ + "Type": Name("Page"), + "Parent": *pagesIndRef, + "MediaBox": mediaBox.Array(), + "Resources": *resIndRef, + "Contents": *contentsIndRef, + }, + ) + + indRef, err := xRefTable.IndRefForNewObject(pageDict) + if err != nil { + return err + } + + if err = AppendPageTree(indRef, 1, pagesDict); err != nil { + return err + } + + ctx.PageCount++ + + return nil +} + +// NUpFromMultipleImages creates pages in NUp-style rendering each image once. +func NUpFromMultipleImages(ctx *Context, fileNames []string, nup *NUp, pagesDict Dict, pagesIndRef *IndirectRef) error { + if nup.PageGrid { + nup.PageDim.Width *= nup.Grid.Width + nup.PageDim.Height *= nup.Grid.Height + } + + xRefTable := ctx.XRefTable + formsResDict := NewDict() + var buf bytes.Buffer + rr := rectsForGrid(nup) + + for i, fileName := range fileNames { + + if i > 0 && i%len(rr) == 0 { + + // Wrap complete nUp page. + if err := wrapUpPage(ctx, nup, formsResDict, buf, pagesDict, pagesIndRef); err != nil { + return err + } + + buf.Reset() + formsResDict = NewDict() + } + + f, err := os.Open(fileName) + if err != nil { + return err + } + + imgIndRef, w, h, err := createImageResource(xRefTable, f) + if err != nil { + return err + } + + if err := f.Close(); err != nil { + return err + } + + formIndRef, err := createNUpForm(xRefTable, imgIndRef, w, h, i) + if err != nil { + return err + } + + formResID := fmt.Sprintf("Fm%d", i) + formsResDict.Insert(formResID, *formIndRef) + + nUpTilePDFBytes(&buf, RectForDim(float64(w), float64(h)), rr[i%len(rr)], formResID, nup) + } + + // Wrap incomplete nUp page. + return wrapUpPage(ctx, nup, formsResDict, buf, pagesDict, pagesIndRef) +} + +func sortedSelectedPages(pages IntSet) []int { + var pageNumbers []int + for k, v := range pages { + if v { + pageNumbers = append(pageNumbers, k) + } + } + sort.Ints(pageNumbers) + return pageNumbers +} + +func (ctx *Context) nupPages(selectedPages IntSet, nup *NUp, pagesDict Dict, pagesIndRef *IndirectRef) error { + var buf bytes.Buffer + xRefTable := ctx.XRefTable + formsResDict := NewDict() + rr := rectsForGrid(nup) + + for i, p := range sortedSelectedPages(selectedPages) { + + if i > 0 && i%len(rr) == 0 { + + // Wrap complete nUp page. + if err := wrapUpPage(ctx, nup, formsResDict, buf, pagesDict, pagesIndRef); err != nil { + return err + } + + buf.Reset() + formsResDict = NewDict() + } + + consolidateRes := true + d, inhPAttrs, err := ctx.PageDict(p, consolidateRes) + if err != nil { + return err + } + if d == nil { + return errors.Errorf("pdfcpu: unknown page number: %d\n", i) + } + + // Retrieve content stream bytes. + bb, err := xRefTable.PageContent(d) + if err == errNoContent { + continue + } + if err != nil { + return err + } + + // Create an object for this resDict in xRefTable. + ir, err := ctx.IndRefForNewObject(inhPAttrs.resources) + if err != nil { + return err + } + + cropBox := inhPAttrs.mediaBox + if inhPAttrs.cropBox != nil { + cropBox = inhPAttrs.cropBox + } + formIndRef, err := createNUpFormForPDFResource(xRefTable, ir, bb, cropBox) + if err != nil { + return err + } + + formResID := fmt.Sprintf("Fm%d", i) + formsResDict.Insert(formResID, *formIndRef) + + // inhPAttrs.mediaBox + nUpTilePDFBytes(&buf, cropBox, rr[i%len(rr)], formResID, nup) + } + + // Wrap incomplete nUp page. + return wrapUpPage(ctx, nup, formsResDict, buf, pagesDict, pagesIndRef) +} + +// NUpFromPDF creates an n-up version of the PDF represented by xRefTable. +func (ctx *Context) NUpFromPDF(selectedPages IntSet, nup *NUp) error { + var mb *Rectangle + if nup.PageDim == nil { + // No page dimensions specified, use mediaBox of page 1. + consolidateRes := false + d, inhPAttrs, err := ctx.PageDict(1, consolidateRes) + if err != nil { + return err + } + if d == nil { + return errors.Errorf("unknown page number: %d\n", 1) + } + mb = inhPAttrs.mediaBox + } else { + mb = RectForDim(nup.PageDim.Width, nup.PageDim.Height) + } + + if nup.PageGrid { + mb.UR.X = mb.LL.X + float64(nup.Grid.Width)*mb.Width() + mb.UR.Y = mb.LL.Y + float64(nup.Grid.Height)*mb.Height() + } + + pagesDict := Dict( + map[string]Object{ + "Type": Name("Pages"), + "Count": Integer(0), + "MediaBox": mb.Array(), + }, + ) + + pagesIndRef, err := ctx.IndRefForNewObject(pagesDict) + if err != nil { + return err + } + + nup.PageDim = &Dim{mb.Width(), mb.Height()} + + if err = ctx.nupPages(selectedPages, nup, pagesDict, pagesIndRef); err != nil { + return err + } + + // Replace original pagesDict. + rootDict, err := ctx.Catalog() + if err != nil { + return err + } + + rootDict.Update("Pages", *pagesIndRef) + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/optimize.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/optimize.go new file mode 100644 index 0000000..87e9346 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/optimize.go @@ -0,0 +1,1214 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + "sort" + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +// Mark all content streams for a page dictionary (for stats). +func identifyPageContent(xRefTable *XRefTable, pageDict Dict, pageObjNumber int) error { + + log.Optimize.Println("identifyPageContent begin") + + o, found := pageDict.Find("Contents") + if !found { + log.Optimize.Println("identifyPageContent end: no \"Contents\"") + return nil + } + + var contentArr Array + + if ir, ok := o.(IndirectRef); ok { + + entry, found := xRefTable.FindTableEntry(ir.ObjectNumber.Value(), ir.GenerationNumber.Value()) + if !found { + return errors.Errorf("identifyPageContent: obj#:%d illegal indRef for Contents\n", pageObjNumber) + } + + contentStreamDict, ok := entry.Object.(StreamDict) + if ok { + contentStreamDict.IsPageContent = true + entry.Object = contentStreamDict + log.Optimize.Printf("identifyPageContent end: ok obj#%d\n", ir.ObjectNumber.Value()) + return nil + } + + contentArr, ok = entry.Object.(Array) + if !ok { + return errors.Errorf("identifyPageContent: obj#:%d page content entry neither stream dict nor array.\n", pageObjNumber) + } + + } else if contentArr, ok = o.(Array); !ok { + return errors.Errorf("identifyPageContent: obj#:%d corrupt page content array\n", pageObjNumber) + } + + for _, c := range contentArr { + + ir, ok := c.(IndirectRef) + if !ok { + return errors.Errorf("identifyPageContent: obj#:%d corrupt page content array entry\n", pageObjNumber) + } + + entry, found := xRefTable.FindTableEntry(ir.ObjectNumber.Value(), ir.GenerationNumber.Value()) + if !found { + return errors.Errorf("identifyPageContent: obj#:%d illegal indRef for Contents\n", pageObjNumber) + } + + contentStreamDict, ok := entry.Object.(StreamDict) + if !ok { + return errors.Errorf("identifyPageContent: obj#:%d page content entry is no stream dict\n", pageObjNumber) + } + + contentStreamDict.IsPageContent = true + entry.Object = contentStreamDict + log.Optimize.Printf("identifyPageContent: ok obj#%d\n", ir.GenerationNumber.Value()) + } + + log.Optimize.Println("identifyPageContent end") + + return nil +} + +// resourcesDictForPageDict returns the resource dict for a page dict if there is any. +func resourcesDictForPageDict(xRefTable *XRefTable, pageDict Dict, pageObjNumber int) (Dict, error) { + + o, found := pageDict.Find("Resources") + if !found { + log.Optimize.Printf("resourcesDictForPageDict end: No resources dict for page object %d, may be inherited\n", pageObjNumber) + return nil, nil + } + + return xRefTable.DereferenceDict(o) +} + +// handleDuplicateFontObject returns nil or the object number of the registered font if it matches this font. +func handleDuplicateFontObject(ctx *Context, fontDict Dict, fName, rName string, objNr, pageNumber int) (*int, error) { + + // Get a slice of all font object numbers for font name. + fontObjNrs, found := ctx.Optimize.Fonts[fName] + if !found { + // There is no registered font with fName. + return nil, nil + } + + // Get the set of font object numbers for pageNumber. + pageFonts := ctx.Optimize.PageFonts[pageNumber] + + // Iterate over all registered font object numbers for font name. + // Check if this font dict matches the font dict of each font object number. + for _, fontObjNr := range fontObjNrs { + + // Get the font object from the lookup table. + fontObject := ctx.Optimize.FontObjects[fontObjNr] + + log.Optimize.Printf("handleDuplicateFontObject: comparing with fontDict Obj %d\n", fontObjNr) + + // Check if the input fontDict matches the fontDict of this fontObject. + ok, err := equalFontDicts(fontObject.FontDict, fontDict, ctx.XRefTable) + if err != nil { + return nil, err + } + + if !ok { + // No match! + continue + } + + // We have detected a redundant font dict! + log.Optimize.Printf("handleDuplicateFontObject: redundant fontObj#:%d basefont %s already registered with obj#:%d !\n", objNr, fName, fontObjNr) + + // Register new page font with pageNumber. + // The font for font object number is used instead of objNr. + pageFonts[fontObjNr] = true + + // Add the resource name of this duplicate font to the list of registered resource names. + fontObject.AddResourceName(rName) + + // Register fontDict as duplicate. + ctx.Optimize.DuplicateFonts[objNr] = fontDict + + // Return the fontObjectNumber that will be used instead of objNr. + return &fontObjNr, nil + } + + return nil, nil +} + +func pageImages(ctx *Context, pageNumber int) IntSet { + + pageImages := ctx.Optimize.PageImages[pageNumber] + + if pageImages == nil { + pageImages = IntSet{} + ctx.Optimize.PageImages[pageNumber] = pageImages + } + + return pageImages +} + +func pageFonts(ctx *Context, pageNumber int) IntSet { + + pageFonts := ctx.Optimize.PageFonts[pageNumber] + + if pageFonts == nil { + pageFonts = IntSet{} + ctx.Optimize.PageFonts[pageNumber] = pageFonts + } + + return pageFonts +} + +func fontName(ctx *Context, fontDict Dict, objNumber int) (prefix, fontName string, err error) { + + var found bool + var o Object + + if *fontDict.Subtype() != "Type3" { + + o, found = fontDict.Find("BaseFont") + if !found { + o, found = fontDict.Find("Name") + if !found { + return "", "", errors.New("pdfcpu: fontName: missing fontDict entries \"BaseFont\" and \"Name\"") + } + } + + } else { + + // Type3 fonts only have Name in V1.0 else use generic name. + + o, found = fontDict.Find("Name") + if !found { + return "", fmt.Sprintf("Type3_%d", objNumber), nil + } + + } + + o, err = ctx.Dereference(o) + if err != nil { + return "", "", err + } + + baseFont, ok := o.(Name) + if !ok { + return "", "", errors.New("pdfcpu: fontName: corrupt fontDict entry BaseFont") + } + + n := string(baseFont) + + // Isolate Postscript prefix. + var p string + + i := strings.Index(n, "+") + + if i > 0 { + p = n[:i] + n = n[i+1:] + } + + return p, n, nil +} + +// Get rid of redundant fonts for given fontResources dictionary. +func optimizeFontResourcesDict(ctx *Context, rDict Dict, pageNumber, pageObjNumber int) error { + + log.Optimize.Printf("optimizeFontResourcesDict begin: page=%d pageObjNumber=%d %s\nPageFonts=%v\n", pageNumber, pageObjNumber, rDict, ctx.Optimize.PageFonts) + + pageFonts := pageFonts(ctx, pageNumber) + + // Iterate over font resource dict. + for rName, v := range rDict { + + indRef, ok := v.(IndirectRef) + if !ok { + return errors.Errorf("pdfcpu: optimizeFontResourcesDict: missing indirect object ref for Font: %s\n", rName) + } + + log.Optimize.Printf("optimizeFontResourcesDict: processing font: %s, %s\n", rName, indRef) + objNr := int(indRef.ObjectNumber) + log.Optimize.Printf("optimizeFontResourcesDict: objectNumber = %d\n", objNr) + + if _, found := ctx.Optimize.FontObjects[objNr]; found { + // This font has already been registered. + //logInfoOptimizePrintf("optimizeFontResourcesDict: Fontobject %d already registered\n", objectNumber) + pageFonts[objNr] = true + continue + } + + // We are dealing with a new font. + // Dereference the font dict. + fontDict, err := ctx.DereferenceDict(indRef) + if err != nil { + return err + } + if fontDict == nil { + continue + } + + log.Optimize.Printf("optimizeFontResourcesDict: fontDict: %s\n", fontDict) + + if fontDict.Type() == nil { + return errors.Errorf("pdfcpu: optimizeFontResourcesDict: missing dict type %s\n", v) + } + + if *fontDict.Type() != "Font" { + return errors.Errorf("pdfcpu: optimizeFontResourcesDict: expected Type=Font, unexpected Type: %s", *fontDict.Type()) + } + + // Get the unique font name. + prefix, fName, err := fontName(ctx, fontDict, objNr) + if err != nil { + return err + } + log.Optimize.Printf("optimizeFontResourcesDict: baseFont: prefix=%s name=%s\n", prefix, fName) + + // Check if fontDict is a duplicate and if so return the object number of the original. + originalObjNr, err := handleDuplicateFontObject(ctx, fontDict, fName, rName, objNr, pageNumber) + if err != nil { + return err + } + + if originalObjNr != nil { + // We have identified a redundant fontDict! + // Update font resource dict so that rName points to the original. + ir := NewIndirectRef(*originalObjNr, 0) + rDict[rName] = *ir + // Increase refCount for *originalObjNr + entry, ok := ctx.FindTableEntryForIndRef(ir) + if ok { + entry.RefCount++ + } + continue + } + + // Register new font dict. + log.Optimize.Printf("optimizeFontResourcesDict: adding new font %s obj#%d\n", fName, objNr) + + fontObjNrs, found := ctx.Optimize.Fonts[fName] + if found { + log.Optimize.Printf("optimizeFontResourcesDict: appending %d to %s\n", objNr, fName) + ctx.Optimize.Fonts[fName] = append(fontObjNrs, objNr) + } else { + ctx.Optimize.Fonts[fName] = []int{objNr} + } + + ctx.Optimize.FontObjects[objNr] = + &FontObject{ + ResourceNames: []string{rName}, + Prefix: prefix, + FontName: fName, + FontDict: fontDict, + } + + pageFonts[objNr] = true + + } + + log.Optimize.Println("optimizeFontResourcesDict end:") + + return nil +} + +// handleDuplicateImageObject returns nil or the object number of the registered image if it matches this image. +func handleDuplicateImageObject(ctx *Context, imageDict *StreamDict, resourceName string, objNr, pageNumber int) (*int, error) { + + // Get the set of image object numbers for pageNumber. + pageImages := ctx.Optimize.PageImages[pageNumber] + + // Process image dict, check if this is a duplicate. + for imageObjNr, imageObject := range ctx.Optimize.ImageObjects { + + log.Optimize.Printf("handleDuplicateImageObject: comparing with imagedict Obj %d\n", imageObjNr) + + // Check if the input imageDict matches the imageDict of this imageObject. + ok, err := equalStreamDicts(imageObject.ImageDict, imageDict, ctx.XRefTable) + if err != nil { + return nil, err + } + + if !ok { + // No match! + continue + } + + // We have detected a redundant image dict. + log.Optimize.Printf("handleDuplicateImageObject: redundant imageObj#:%d already registered with obj#:%d !\n", objNr, imageObjNr) + + // Register new page image for pageNumber. + // The image for image object number is used instead of objNr. + pageImages[imageObjNr] = true + + // Add the resource name of this duplicate image to the list of registered resource names. + imageObject.AddResourceName(resourceName) + + // Register imageDict as duplicate. + ctx.Optimize.DuplicateImages[objNr] = imageDict + + // Return the imageObjectNumber that will be used instead of objNr. + return &imageObjNr, nil + } + + return nil, nil +} + +// Get rid of redundant XObjects e.g. embedded images. +func optimizeXObjectResourcesDict(ctx *Context, rDict Dict, pageNumber, pageObjNumber int) error { + + log.Optimize.Printf("optimizeXObjectResourcesDict page#%dbegin: %s\n", pageObjNumber, rDict) + + pageImages := pageImages(ctx, pageNumber) + + // Iterate over XObject resource dict. + for rName, v := range rDict { + + indRef, ok := v.(IndirectRef) + if !ok { + return errors.Errorf("pdfcpu: optimizeXObjectResourcesDict: missing indirect object ref for resourceId: %s", rName) + } + + log.Optimize.Printf("optimizeXObjectResourcesDict: processing xobject: %s, %s\n", rName, indRef) + objNr := int(indRef.ObjectNumber) + log.Optimize.Printf("optimizeXObjectResourcesDict: objectNumber = %d\n", objNr) + + // We are dealing with a new XObject.. + // Dereference the XObject stream dict. + + osd, _, err := ctx.DereferenceStreamDict(indRef) + if err != nil { + return err + } + if osd == nil { + continue + } + + log.Optimize.Printf("optimizeXObjectResourcesDict: dereferenced obj:%d\n%s", objNr, osd) + + if osd.Dict.Subtype() == nil { + return errors.Errorf("pdfcpu: optimizeXObjectResourcesDict: missing stream dict Subtype %s\n", v) + } + + if *osd.Dict.Subtype() == "Image" { + + // Already registered image object that appears in different resources dicts. + if _, found := ctx.Optimize.ImageObjects[objNr]; found { + // This image has already been registered. + //log.Optimize.Printf("optimizeXObjectResourcesDict: Imageobject %d already registered\n", objNr) + pageImages[objNr] = true + continue + } + + // Check if image is a duplicate and if so return the object number of the original. + originalObjNr, err := handleDuplicateImageObject(ctx, osd, rName, objNr, pageNumber) + if err != nil { + return err + } + + if originalObjNr != nil { + // We have identified a redundant image! + // Update xobject resource dict so that rName points to the original. + ir := NewIndirectRef(*originalObjNr, 0) + rDict[rName] = *ir + // Increase refCount for *originalObjNr + entry, ok := ctx.FindTableEntryForIndRef(ir) + if ok { + entry.RefCount++ + } + continue + } + + // Register new image dict. + log.Optimize.Printf("optimizeXObjectResourcesDict: adding new image obj#%d\n", objNr) + + ctx.Optimize.ImageObjects[objNr] = + &ImageObject{ + ResourceNames: []string{rName}, + ImageDict: osd, + } + + pageImages[objNr] = true + continue + } + + if *osd.Subtype() != "Form" { + log.Optimize.Printf("optimizeXObjectResourcesDict: unexpected stream dict Subtype %s\n", *osd.Dict.Subtype()) + continue + } + + // Process form dict + log.Optimize.Printf("optimizeXObjectResourcesDict: parsing form dict obj:%d\n", objNr) + parseResourcesDict(ctx, osd.Dict, pageNumber, objNr) + } + + log.Optimize.Println("optimizeXObjectResourcesDict end") + + return nil +} + +// Optimize given resource dictionary by removing redundant fonts and images. +func optimizeResources(ctx *Context, resourcesDict Dict, pageNumber, pageObjNumber int) error { + + log.Optimize.Printf("optimizeResources begin: pageNumber=%d pageObjNumber=%d\n", pageNumber, pageObjNumber) + + if resourcesDict == nil { + log.Optimize.Printf("optimizeResources end: No resources dict available") + return nil + } + + // Process Font resource dict, get rid of redundant fonts. + o, found := resourcesDict.Find("Font") + if found { + + d, err := ctx.DereferenceDict(o) + if err != nil { + return err + } + + if d == nil { + return errors.Errorf("pdfcpu: optimizeResources: font resource dict is null for page %d pageObj %d\n", pageNumber, pageObjNumber) + } + + if err = optimizeFontResourcesDict(ctx, d, pageNumber, pageObjNumber); err != nil { + return err + } + + } + + // Note: An optional ExtGState resource dict may contain binary content in the following entries: "SMask", "HT". + + // Process XObject resource dict, get rid of redundant images. + o, found = resourcesDict.Find("XObject") + if found { + + d, err := ctx.DereferenceDict(o) + if err != nil { + return err + } + + if d == nil { + return errors.Errorf("pdfcpu: optimizeResources: xobject resource dict is null for page %d pageObj %d\n", pageNumber, pageObjNumber) + } + + if err = optimizeXObjectResourcesDict(ctx, d, pageNumber, pageObjNumber); err != nil { + return err + } + + } + + log.Optimize.Println("optimizeResources end") + + return nil +} + +// Process the resources dictionary for given page number and optimize by removing redundant resources. +func parseResourcesDict(ctx *Context, pageDict Dict, pageNumber, pageObjNumber int) error { + + if ctx.Optimize.Cache[pageObjNumber] { + return nil + } + ctx.Optimize.Cache[pageObjNumber] = true + + // The logical pageNumber is pageNumber+1. + log.Optimize.Printf("parseResourcesDict begin page: %d, object:%d\n", pageNumber+1, pageObjNumber) + + // Get resources dict for this page. + d, err := resourcesDictForPageDict(ctx.XRefTable, pageDict, pageObjNumber) + if err != nil { + return err + } + + // dict may be nil for inherited resource dicts. + if d != nil { + + // Optimize image and font resources. + if err = optimizeResources(ctx, d, pageNumber, pageObjNumber); err != nil { + return err + } + + } + + log.Optimize.Printf("parseResourcesDict end page: %d, object:%d\n", pageNumber+1, pageObjNumber) + + return nil +} + +// Iterate over all pages and optimize resources. +func parsePagesDict(ctx *Context, pagesDict Dict, pageNumber int) (int, error) { + + log.Optimize.Printf("parsePagesDict begin (next page=%d): %s\n", pageNumber+1, pagesDict) + + // Get number of pages of this PDF file. + count, found := pagesDict.Find("Count") + if !found { + return 0, errors.New("pdfcpu: parsePagesDict: missing Count") + } + + log.Optimize.Printf("parsePagesDict: This page node has %d pages\n", int(count.(Integer))) + + ctx.Optimize.Cache = map[int]bool{} + + // Iterate over page tree. + for _, v := range pagesDict.ArrayEntry("Kids") { + + // Dereference next page node dict. + ir, _ := v.(IndirectRef) + log.Optimize.Printf("parsePagesDict PageNode: %s\n", ir) + o, err := ctx.Dereference(ir) + if err != nil { + return 0, errors.Wrap(err, "parsePagesDict: can't locate Pagedict or Pagesdict") + } + + pageNodeDict := o.(Dict) + dictType := pageNodeDict.Type() + if dictType == nil { + return 0, errors.New("pdfcpu: parsePagesDict: Missing dict type") + } + + // Note: Pages may contain a to be inherited ResourcesDict. + + if *dictType == "Pages" { + + // Recurse over pagetree and optimize resources. + pageNumber, err = parsePagesDict(ctx, pageNodeDict, pageNumber) + if err != nil { + return 0, err + } + + continue + } + + if *dictType != "Page" { + return 0, errors.Errorf("pdfcpu: parsePagesDict: Unexpected dict type: %s\n", *dictType) + } + + // Process page dict. + + // Mark page content streams for stats. + if err = identifyPageContent(ctx.XRefTable, pageNodeDict, int(ir.ObjectNumber)); err != nil { + return 0, err + } + + if err := ctx.deleteDictEntry(pageNodeDict, "PieceInfo"); err != nil { + return 0, err + } + + // Parse and optimize resource dict for one page. + if err = parseResourcesDict(ctx, pageNodeDict, pageNumber, int(ir.ObjectNumber)); err != nil { + return 0, err + } + + pageNumber++ + } + + log.Optimize.Printf("parsePagesDict end: %s\n", pagesDict) + + return pageNumber, nil +} + +func traverse(xRefTable *XRefTable, value Object, duplObjs IntSet) error { + + if indRef, ok := value.(IndirectRef); ok { + duplObjs[int(indRef.ObjectNumber)] = true + o, err := xRefTable.Dereference(indRef) + if err != nil { + return err + } + traverseObjectGraphAndMarkDuplicates(xRefTable, o, duplObjs) + } + if d, ok := value.(Dict); ok { + traverseObjectGraphAndMarkDuplicates(xRefTable, d, duplObjs) + } + if sd, ok := value.(StreamDict); ok { + traverseObjectGraphAndMarkDuplicates(xRefTable, sd, duplObjs) + } + if a, ok := value.(Array); ok { + traverseObjectGraphAndMarkDuplicates(xRefTable, a, duplObjs) + } + + return nil +} + +// Traverse the object graph for a Object and mark all objects as potential duplicates. +func traverseObjectGraphAndMarkDuplicates(xRefTable *XRefTable, obj Object, duplObjs IntSet) error { + + log.Optimize.Printf("traverseObjectGraphAndMarkDuplicates begin type=%T\n", obj) + + switch x := obj.(type) { + + case Dict: + log.Optimize.Println("traverseObjectGraphAndMarkDuplicates: dict.") + for _, value := range x { + if err := traverse(xRefTable, value, duplObjs); err != nil { + return err + } + } + + case StreamDict: + log.Optimize.Println("traverseObjectGraphAndMarkDuplicates: streamDict.") + for _, value := range x.Dict { + if err := traverse(xRefTable, value, duplObjs); err != nil { + return err + } + } + + case Array: + log.Optimize.Println("traverseObjectGraphAndMarkDuplicates: arr.") + for _, value := range x { + if err := traverse(xRefTable, value, duplObjs); err != nil { + return err + } + } + } + + log.Optimize.Println("traverseObjectGraphAndMarkDuplicates end") + + return nil +} + +// Identify and mark all potential duplicate objects. +func calcRedundantObjects(ctx *Context) error { + + log.Optimize.Println("calcRedundantObjects begin") + + for i, fontDict := range ctx.Optimize.DuplicateFonts { + ctx.Optimize.DuplicateFontObjs[i] = true + // Identify and mark all involved potential duplicate objects for a redundant font. + if err := traverseObjectGraphAndMarkDuplicates(ctx.XRefTable, fontDict, ctx.Optimize.DuplicateFontObjs); err != nil { + return err + } + } + + for i, sd := range ctx.Optimize.DuplicateImages { + ctx.Optimize.DuplicateImageObjs[i] = true + // Identify and mark all involved potential duplicate objects for a redundant image. + if err := traverseObjectGraphAndMarkDuplicates(ctx.XRefTable, *sd, ctx.Optimize.DuplicateImageObjs); err != nil { + return err + } + } + + log.Optimize.Println("calcRedundantObjects end") + + return nil +} + +// Iterate over all pages and optimize resources. +// Get rid of duplicate embedded fonts and images. +func optimizeFontAndImages(ctx *Context) error { + + log.Optimize.Println("optimizeFontAndImages begin") + + // Get a reference to the PDF indirect reference of the page tree root dict. + indRefPages, err := ctx.Pages() + if err != nil { + return err + } + + // Dereference and get a reference to the page tree root dict. + pageTreeRootDict, err := ctx.XRefTable.DereferenceDict(*indRefPages) + if err != nil { + return err + } + + // Detect the number of pages of this PDF file. + pageCount := pageTreeRootDict.IntEntry("Count") + if pageCount == nil { + return errors.New("pdfcpu: optimizeFontAndImagess: missing \"Count\" in page root dict") + } + + // If PageCount already set by validation doublecheck. + if ctx.PageCount > 0 && ctx.PageCount != *pageCount { + return errors.New("pdfcpu: optimizeFontAndImagess: unexpected page root dict pageCount discrepancy") + } + + // If we optimize w/o prior validation, set PageCount. + if ctx.PageCount == 0 { + ctx.PageCount = *pageCount + } + + // Prepare optimization environment. + ctx.Optimize.PageFonts = make([]IntSet, ctx.PageCount) + ctx.Optimize.PageImages = make([]IntSet, ctx.PageCount) + + // Iterate over page dicts and optimize resources. + _, err = parsePagesDict(ctx, pageTreeRootDict, 0) + if err != nil { + return err + } + + // Identify all duplicate objects. + if err = calcRedundantObjects(ctx); err != nil { + return err + } + + log.Optimize.Println("optimizeFontAndImages end") + + return nil +} + +// Return stream length for font file object. +func streamLengthFontFile(xRefTable *XRefTable, indirectRef *IndirectRef) (*int64, error) { + + log.Optimize.Println("streamLengthFontFile begin") + + objectNumber := indirectRef.ObjectNumber + + sd, _, err := xRefTable.DereferenceStreamDict(*indirectRef) + if err != nil { + return nil, err + } + + if sd == nil || (*sd).StreamLength == nil { + return nil, errors.Errorf("pdfcpu: streamLengthFontFile: fontFile Streamlength is nil for object %d\n", objectNumber) + } + + log.Optimize.Println("streamLengthFontFile end") + + return (*sd).StreamLength, nil +} + +// Calculate amount of memory used by embedded fonts for stats. +func calcEmbeddedFontsMemoryUsage(ctx *Context) error { + + log.Optimize.Printf("calcEmbeddedFontsMemoryUsage begin: %d fontObjects\n", len(ctx.Optimize.FontObjects)) + + fontFileIndRefs := map[IndirectRef]bool{} + + var objectNumbers []int + + // Sorting unnecessary. + for k := range ctx.Optimize.FontObjects { + objectNumbers = append(objectNumbers, k) + } + sort.Ints(objectNumbers) + + // Iterate over all embedded font objects and record font file references. + for _, objectNumber := range objectNumbers { + + fontObject := ctx.Optimize.FontObjects[objectNumber] + + // Only embedded fonts have binary data. + if !fontObject.Embedded() { + continue + } + + if err := processFontFilesForFontDict(ctx.XRefTable, fontObject.FontDict, objectNumber, fontFileIndRefs); err != nil { + return err + } + } + + // Iterate over font file references and calculate total font size. + for ir := range fontFileIndRefs { + streamLength, err := streamLengthFontFile(ctx.XRefTable, &ir) + if err != nil { + return err + } + ctx.Read.BinaryFontSize += *streamLength + } + + log.Optimize.Println("calcEmbeddedFontsMemoryUsage end") + + return nil +} + +// fontDescriptorFontFileIndirectObjectRef returns the indirect object for the font file for given font descriptor. +func fontDescriptorFontFileIndirectObjectRef(fontDescriptorDict Dict) *IndirectRef { + + log.Optimize.Println("fontDescriptorFontFileIndirectObjectRef begin") + + ir := fontDescriptorDict.IndirectRefEntry("FontFile") + + if ir == nil { + ir = fontDescriptorDict.IndirectRefEntry("FontFile2") + } + + if ir == nil { + ir = fontDescriptorDict.IndirectRefEntry("FontFile3") + } + + if ir == nil { + //logInfoReader.Printf("FontDescriptorFontFileLength: FontDescriptor dict without fontFile: \n%s\n", fontDescriptorDict) + } + + log.Optimize.Println("FontDescriptorFontFileIndirectObjectRef end") + + return ir +} + +func trivialFontDescriptor(xRefTable *XRefTable, fontDict Dict, objNr int) (Dict, error) { + + o, ok := fontDict.Find("FontDescriptor") + if !ok { + return nil, nil + } + + // fontDescriptor directly available. + + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return nil, err + } + + if d == nil { + return nil, errors.Errorf("pdfcpu: trivialFontDescriptor: FontDescriptor is null for font object %d\n", objNr) + } + + if d.Type() != nil && *d.Type() != "FontDescriptor" { + return nil, errors.Errorf("pdfcpu: trivialFontDescriptor: FontDescriptor dict incorrect dict type for font object %d\n", objNr) + } + + return d, nil +} + +// FontDescriptor gets the font descriptor for this font. +func fontDescriptor(xRefTable *XRefTable, fontDict Dict, objNr int) (Dict, error) { + + log.Optimize.Println("fontDescriptor begin") + + d, err := trivialFontDescriptor(xRefTable, fontDict, objNr) + if err != nil { + return nil, err + } + if d != nil { + return d, nil + } + + // Try to access a fontDescriptor in a Descendent font for Type0 fonts. + + o, ok := fontDict.Find("DescendantFonts") + if !ok { + //logErrorOptimize.Printf("FontDescriptor: Neither FontDescriptor nor DescendantFonts for font object %d\n", objectNumber) + return nil, nil + } + + // A descendant font is contained in an array of size 1. + + a, err := xRefTable.DereferenceArray(o) + if err != nil || a == nil { + return nil, errors.Errorf("pdfcpu: fontDescriptor: DescendantFonts: IndirectRef or Array wth length 1 expected for font object %d\n", objNr) + } + if len(a) > 1 { + return nil, errors.Errorf("pdfcpu: fontDescriptor: DescendantFonts Array length > 1 %v\n", a) + } + + // dict is the fontDict of the descendant font. + d, err = xRefTable.DereferenceDict(a[0]) + if err != nil { + return nil, errors.Errorf("pdfcpu: fontDescriptor: No descendant font dict for %v\n", a) + } + if d == nil { + return nil, errors.Errorf("pdfcpu: fontDescriptor: descendant font dict is null for %v\n", a) + } + + if *d.Type() != "Font" { + return nil, errors.Errorf("pdfcpu: fontDescriptor: font dict with incorrect dict type for %v\n", d) + } + + o, ok = d.Find("FontDescriptor") + if !ok { + log.Optimize.Printf("fontDescriptor: descendant font not embedded %s\n", d) + return nil, nil + } + + d, err = xRefTable.DereferenceDict(o) + if err != nil { + return nil, errors.Errorf("pdfcpu: fontDescriptor: No FontDescriptor dict for font object %d\n", objNr) + } + + log.Optimize.Println("fontDescriptor end") + + return d, nil +} + +// Record font file objects referenced by this fonts font descriptor for stats and size calculation. +func processFontFilesForFontDict(xRefTable *XRefTable, fontDict Dict, objectNumber int, indRefsMap map[IndirectRef]bool) error { + + log.Optimize.Println("processFontFilesForFontDict begin") + + // Note: + // "ToUnicode" is also an entry containing binary content that could be inspected for duplicate content. + + d, err := fontDescriptor(xRefTable, fontDict, objectNumber) + if err != nil { + return err + } + + if d != nil { + if ir := fontDescriptorFontFileIndirectObjectRef(d); ir != nil { + indRefsMap[*ir] = true + } + } + + log.Optimize.Println("processFontFilesForFontDict end") + + return nil +} + +// Calculate amount of memory used by duplicate embedded fonts for stats. +func calcRedundantEmbeddedFontsMemoryUsage(ctx *Context) error { + + log.Optimize.Println("calcRedundantEmbeddedFontsMemoryUsage begin") + + fontFileIndRefs := map[IndirectRef]bool{} + + // Iterate over all duplicate fonts and record font file references. + for objectNumber, fontDict := range ctx.Optimize.DuplicateFonts { + + // Duplicate Fonts have to be embedded, so no check here. + if err := processFontFilesForFontDict(ctx.XRefTable, fontDict, objectNumber, fontFileIndRefs); err != nil { + return err + } + + } + + // Iterate over font file references and calculate total font size. + for ir := range fontFileIndRefs { + + streamLength, err := streamLengthFontFile(ctx.XRefTable, &ir) + if err != nil { + return err + } + + ctx.Read.BinaryFontDuplSize += *streamLength + } + + log.Optimize.Println("calcRedundantEmbeddedFontsMemoryUsage end") + + return nil +} + +// Calculate amount of memory used by embedded fonts and duplicate embedded fonts for stats. +func calcFontBinarySizes(ctx *Context) error { + + log.Optimize.Println("calcFontBinarySizes begin") + + if err := calcEmbeddedFontsMemoryUsage(ctx); err != nil { + return err + } + + if err := calcRedundantEmbeddedFontsMemoryUsage(ctx); err != nil { + return err + } + + log.Optimize.Println("calcFontBinarySizes end") + + return nil +} + +// Calculate amount of memory used by images and duplicate images for stats. +func calcImageBinarySizes(ctx *Context) { + + log.Optimize.Println("calcImageBinarySizes begin") + + // Calc memory usage for images. + for _, imageObject := range ctx.Optimize.ImageObjects { + ctx.Read.BinaryImageSize += *imageObject.ImageDict.StreamLength + } + + // Calc memory usage for duplicate images. + for _, imageDict := range ctx.Optimize.DuplicateImages { + ctx.Read.BinaryImageDuplSize += *imageDict.StreamLength + } + + log.Optimize.Println("calcImageBinarySizes end") +} + +// Calculate memory usage of binary data for stats. +func calcBinarySizes(ctx *Context) error { + + log.Optimize.Println("calcBinarySizes begin") + + // Calculate font memory usage for stats. + if err := calcFontBinarySizes(ctx); err != nil { + return err + } + + // Calculate image memory usage for stats. + calcImageBinarySizes(ctx) + + // Note: Content streams also represent binary content. + + log.Optimize.Println("calcBinarySizes end") + + return nil +} + +func fixDeepDict(ctx *Context, d Dict, objNr, genNr int) error { + + for k, v := range d { + ir, err := fixDeepObject(ctx, v) + if err != nil { + return err + } + if ir != nil { + d[k] = *ir + } + } + + return nil +} + +func fixDeepArray(ctx *Context, a Array, objNr, genNr int) error { + + for i, v := range a { + ir, err := fixDeepObject(ctx, v) + if err != nil { + return err + } + if ir != nil { + a[i] = *ir + } + } + + return nil +} + +func fixDirectObject(ctx *Context, o Object) error { + + switch o := o.(type) { + + case Dict: + for k, v := range o { + ir, err := fixDeepObject(ctx, v) + if err != nil { + return err + } + if ir != nil { + o[k] = *ir + } + } + + case Array: + for i, v := range o { + ir, err := fixDeepObject(ctx, v) + if err != nil { + return err + } + if ir != nil { + o[i] = *ir + } + } + + } + + return nil +} + +func fixIndirectObject(ctx *Context, ir *IndirectRef) error { + + objNr := int(ir.ObjectNumber) + genNr := int(ir.GenerationNumber) + + if ctx.Optimize.Cache[objNr] { + return nil + } + ctx.Optimize.Cache[objNr] = true + + entry, found := ctx.Find(objNr) + if !found { + return nil + } + + if entry.Free { + // This is a reference to a free object that needs to be fixed. + + //fmt.Printf("fixNullObject: #%d g%d\n", objNr, genNr) + + if ctx.Optimize.NullObjNr == nil { + nr, err := ctx.InsertObject(nil) + if err != nil { + return err + } + ctx.Optimize.NullObjNr = &nr + } + + ir.ObjectNumber = Integer(*ctx.Optimize.NullObjNr) + + return nil + } + + var err error + + switch o := entry.Object.(type) { + + case Dict: + err = fixDeepDict(ctx, o, objNr, genNr) + + case StreamDict: + err = fixDeepDict(ctx, o.Dict, objNr, genNr) + + case Array: + err = fixDeepArray(ctx, o, objNr, genNr) + + } + + return err +} + +func fixDeepObject(ctx *Context, o Object) (*IndirectRef, error) { + + ir, ok := o.(IndirectRef) + if !ok { + return nil, fixDirectObject(ctx, o) + } + + err := fixIndirectObject(ctx, &ir) + return &ir, err +} + +func fixReferencesToFreeObjects(ctx *Context) error { + return fixDirectObject(ctx, ctx.RootDict) +} + +// OptimizeXRefTable optimizes an xRefTable by locating and getting rid of redundant embedded fonts and images. +func OptimizeXRefTable(ctx *Context) error { + + log.Info.Println("optimizing fonts & images") + + log.Optimize.Println("optimizeXRefTable begin") + + // Sometimes free objects are used although they are part of the free object list. + // Replace references to free xref table entries with a reference to a NULL object. + if err := fixReferencesToFreeObjects(ctx); err != nil { + return err + } + + // Get rid of duplicate embedded fonts and images. + if err := optimizeFontAndImages(ctx); err != nil { + return err + } + + // Get rid of PieceInfo dict from root. + if err := ctx.deleteDictEntry(ctx.RootDict, "PieceInfo"); err != nil { + return err + } + + // Calculate memory usage of binary content for stats. + if err := calcBinarySizes(ctx); err != nil { + return err + } + + ctx.Optimized = true + + log.Optimize.Println("optimizeXRefTable end") + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/pages.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/pages.go new file mode 100644 index 0000000..7c4b6b9 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/pages.go @@ -0,0 +1,170 @@ +/* +Copyright 2020 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "github.com/pdfcpu/pdfcpu/pkg/filter" + "github.com/pkg/errors" +) + +// PageContent returns the content in PDF syntax for page dict d. +func (xRefTable *XRefTable) PageContent(d Dict) ([]byte, error) { + + o, _ := d.Find("Contents") + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return nil, err + } + + bb := []byte{} + + switch o := o.(type) { + + case StreamDict: + // no further processing. + err := o.Decode() + if err == filter.ErrUnsupportedFilter { + return nil, errors.New("pdfcpu: unsupported filter: unable to decode content") + } + if err != nil { + return nil, err + } + + bb = append(bb, o.Content...) + + case Array: + // process array of content stream dicts. + for _, o := range o { + if o == nil { + continue + } + o, _, err := xRefTable.DereferenceStreamDict(o) + if err != nil { + return nil, err + } + if o == nil { + continue + } + err = o.Decode() + if err == filter.ErrUnsupportedFilter { + return nil, errors.New("pdfcpu: unsupported filter: unable to decode content") + } + if err != nil { + return nil, err + } + bb = append(bb, o.Content...) + } + + default: + return nil, errors.Errorf("pdfcpu: page content must be stream dict or array") + } + + if len(bb) == 0 { + return nil, errNoContent + } + + return bb, nil +} + +func migratePageDict(d Dict, ctx, ctxDest *Context, migrated map[int]int) error { + var err error + for k, v := range d { + if k == "Parent" { + continue + } + if d[k], err = migrateObject(v, ctx, ctxDest, migrated); err != nil { + return err + } + } + return nil +} + +// AddPages adds pages and corresponding resources from otherXRefTable to xRefTable. +func AddPages(ctx, ctxDest *Context, pages []int, usePgCache bool) error { + + pagesIndRef, err := ctxDest.Pages() + if err != nil { + return err + } + + // This is the page tree root. + pagesDict, err := ctxDest.DereferenceDict(*pagesIndRef) + if err != nil { + return err + } + + pageCache := map[int]*IndirectRef{} + migrated := map[int]int{} + + for _, i := range pages { + + if usePgCache { + if indRef, ok := pageCache[i]; ok { + if err := AppendPageTree(indRef, 1, pagesDict); err != nil { + return err + } + continue + } + } + + // Move page i and required resources into new context. + + consolidateRes := true + d, inhPAttrs, err := ctx.PageDict(i, consolidateRes) + if err != nil { + return err + } + if d == nil { + return errors.Errorf("pdfcpu: unknown page number: %d\n", i) + } + //log.Write.Printf("AddPages:\n%s\n", inhPAttrs.resources) + + //fmt.Printf("migrresDict bef: \n%s", d) + + d = d.Clone().(Dict) + + d["Resources"] = inhPAttrs.resources + d["Parent"] = *pagesIndRef + + // Migrate external page dict into ctxDest. + if err := migratePageDict(d, ctx, ctxDest, migrated); err != nil { + return err + } + + // Handle inherited page attributes. + d["MediaBox"] = inhPAttrs.mediaBox.Array() + if inhPAttrs.rotate%360 > 0 { + d["Rotate"] = Integer(inhPAttrs.rotate) + } + + indRef, err := ctxDest.IndRefForNewObject(d) + if err != nil { + return err + } + + if err := AppendPageTree(indRef, 1, pagesDict); err != nil { + return err + } + + if usePgCache { + pageCache[i] = indRef + } + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/paperSize.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/paperSize.go new file mode 100644 index 0000000..d981235 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/paperSize.go @@ -0,0 +1,208 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +// PaperSize is a map of known paper sizes in user units (=72 dpi pixels). +var PaperSize = map[string]*Dim{ + + // ISO 216:1975 A + "4A0": {4768, 6741}, // 66 1/4" x 93 5/8" 1682 x 2378 mm + "2A0": {3370, 4768}, // 46 3/4" x 66 1/4" 1189 x 1682 mm + "A0": {2384, 3370}, // 33" x 46 3/4" 841 x 1189 mm + "A1": {1684, 2384}, // 23 3/8" x 33" 594 x 841 mm + "A2": {1191, 1684}, // 16 1/2" x 23 3/8" 420 x 594 mm + "A3": {842, 1191}, // 11 3/4" x 16 1/2" 297 x 420 mm + "A4": {595, 842}, // 8 1/4" x 11 3/4" 210 x 297 mm + "A5": {420, 595}, // 5 7/8" x 8 1/4" 148 x 210 mm + "A6": {298, 420}, // 4 1/8" x 5 7/8" 105 x 148 mm + "A7": {210, 298}, // 2 7/8" x 4 1/8" 74 x 105 mm + "A8": {147, 210}, // 2" x 2 7/8" 52 x 74 mm + "A9": {105, 147}, // 1 1/2" x 2" 37 x 52 mm + "A10": {74, 105}, // 1" x 1 1/2" 26 x 37 mm + + // ISO 216:1975 B + "B0+": {3170, 4479}, // 44" x 62 1/4" 1118 x 1580 mm + "B0": {2835, 4008}, // 39 3/8" x 55 3/4" 1000 x 1414 mm + "B1+": {2041, 2892}, // 28 3/8" x 40 1/8" 720 x 1020 mm + "B1": {2004, 2835}, // 27 3/4" x 39 3/8" 707 x 1000 mm + "B2+": {1474, 2041}, // 20 1/2" x 28 3/8" 520 x 720 mm + "B2": {1417, 2004}, // 19 3/4" x 27 3/4" 500 x 707 mm + "B3": {1001, 1417}, // 13 7/8" x 19 3/4" 353 x 500 mm + "B4": {709, 1001}, // 9 7/8" x 13 7/8" 250 x 353 mm + "B5": {499, 709}, // 7" x 9 7/8" 176 x 250 mm + "B6": {354, 499}, // 4 7/8" x 7" 125 x 176 mm + "B7": {249, 354}, // 3 1/2" x 4 7/8" 88 x 125 mm + "B8": {176, 249}, // 2 1/2" x 3 1/2" 62 x 88 mm + "B9": {125, 176}, // 1 3/4" x 2 1/2" 44 x 62 mm + "B10": {88, 125}, // 1 1/4" x 1 3/4" 31 x 44 mm + + // ISO 269:1985 envelopes aka ISO C + "C0": {2599, 3677}, // 36" x 51" 917 x 1297 mm + "C1": {1837, 2599}, // 25 1/2" x 36" 648 x 917 mm + "C2": {1298, 1837}, // 18" x 25 1/2" 458 x 648 mm + "C3": {918, 1298}, // 12 3/4" x 18" 324 x 458 mm + "C4": {649, 918}, // 9" x 12 3/4" 229 x 324 mm + "C5": {459, 649}, // 6 3/8" x 9" 162 x 229 mm + "C6": {323, 459}, // 4 1/2" x 6 3/8" 114 x 162 mm + "C7": {230, 323}, // 3 3/16" x 4 1/2" 81 x 114 mm + "C8": {162, 230}, // 2 1/4" x 3 3/16 57 x 81 mm + "C9": {113, 162}, // 1 5/8" x 2 1/4" 40 x 57 mm + "C10": {79, 113}, // 1 1/8" x 1 5/8" 28 x 40 mm + + // ISO 217:2013 untrimmed raw paper + "RA0": {2438, 3458}, // 33.9" x 48.0" 860 x 1220 mm + "RA1": {1729, 2438}, // 24.0" x 33.9" 610 x 860 mm + "RA2": {1219, 1729}, // 16.9" x 24.0" 430 x 610 mm + "RA3": {865, 1219}, // 12.0" x 16.9" 305 x 430 mm + "RA4": {610, 865}, // 8.5" x 12.0" 215 x 305 mm + + "SRA0": {2551, 3628}, // 35.4" x 50.4" 900 x 1280 mm + "SRA1": {1814, 2551}, // 25.2" x 35.4" 640 x 900 mm + "SRA2": {1276, 1814}, // 17.7" x 25.2" 450 x 640 mm + "SRA3": {907, 1276}, // 12.6" x 17.7" 320 x 450 mm + "SRA4": {638, 907}, // 8.9" x 12.6" 225 x 320 mm + + "SRA1+": {2835, 4008}, // 26.0" x 36.2" 660 x 920 mm + "SRA2+": {1361, 1843}, // 18.9" x 25.6" 480 x 650 mm + "SRA3+": {907, 1304}, // 12.6" x 18.1" 320 x 460 mm + "SRA3++": {2835, 4008}, // 12.6" x 18.3" 320 x 464 mm + + // American + "SuperB": {936, 1368}, // 13" x 19" + "B+": {936, 1368}, + + "Tabloid": {791, 1225}, // 11" x 17" ANSIB, DobleCarta + "ExtraTabloid": {865, 1296}, // 12" x 18" ARCHB, Arch2 + "Ledger": {1225, 791}, // 17" x 11" ANSIB + "Legal": {612, 1009}, // 8 1/2" x 14" + + "GovLegal": {612, 936}, // 8 1/2" x 13" + "Oficio": {612, 936}, + "Folio": {612, 936}, + + "Letter": {612, 791}, // 8 1/2" x 11" ANSIA + "Carta": {612, 791}, + "AmericanQuarto": {612, 791}, + + "DobleCarta": {791, 1225}, // 11" x 17" Tabloid, ANSIB + + "GovLetter": {576, 757}, // 8" x 10 1/2" + "Executive": {522, 756}, // 7 1/4" x 10 1/2" + + "HalfLetter": {397, 612}, // 5 1/2" x 8 1/2" + "Memo": {397, 612}, + "Statement": {397, 612}, + "Stationary": {397, 612}, + + "JuniorLegal": {360, 576}, // 5" x 8" + "IndexCard": {360, 576}, + + "Photo": {288, 432}, // 4" x 6" + + // ANSI/ASME Y14.1 + "ANSIA": {612, 791}, // 8 1/2" x 11" Letter, Carta, AmericanQuarto + "ANSIB": {791, 1225}, // 11" x 17" Ledger, Tabloid, DobleCarta + "ANSIC": {1225, 1585}, // 17" x 22" + "ANSID": {1585, 2449}, // 22" x 34" + "ANSIE": {2449, 3170}, // 34" x 44" + "ANSIF": {2016, 2880}, // 28" x 40" + + // ANSI/ASME Y14.1 Architectural series + "ARCHA": {649, 865}, // 9" x 12" Arch 1 + "ARCHB": {865, 1296}, // 12" x 18" Arch 2, ExtraTabloide + "ARCHC": {1296, 1729}, // 18" x 24" Arch 3 + "ARCHD": {1729, 2591}, // 24" x 36" Arch 4 + "ARCHE": {2591, 3456}, // 36" x 48" Arch 6 + "ARCHE1": {2160, 3025}, // 30" x 42" Arch 5 + "ARCHE2": {1871, 2736}, // 26" x 38" + "ARCHE3": {1945, 2809}, // 27" x 39" + + "Arch1": {649, 865}, // 9" x 12" ARCHA + "Arch2": {865, 1296}, // 12" x 18" ARCHB, ExtraTabloide + "Arch3": {1296, 1729}, // 18" x 24" ARCHC + "Arch4": {1729, 2591}, // 24" x 36" ARCHD + "Arch5": {2160, 3025}, // 30" x 42" ARCHE1 + "Arch6": {2591, 3456}, // 36" x 48" ARCHE + + // American Uncut + "Bond": {1584, 1224}, // 22" x 17" + "Book": {2736, 1800}, // 38" x 25" + "Cover": {1872, 1440}, // 26" x 20" + "Index": {2196, 1836}, // 30 1/2" x 25 1/2" + + "Newsprint": {2592, 1728}, // 36" x 24" + "Tissue": {2592, 1728}, + + "Offset": {2736, 1800}, // 38" x 25" + "Text": {2736, 1800}, + + // English Uncut + "Crown": {1170, 1512}, // 16 1/4" x 21" + "DoubleCrown": {1440, 2160}, // 20" x 30" + "Quad": {2160, 2880}, // 30" x 40" + "Demy": {1242, 1620}, // 17 3/4" x 22 1/2" + "DoubleDemy": {1620, 2556}, // 22 1/2" x 35 1/2" + "Medium": {1314, 1656}, // 18 1/4" x 23" + "Royal": {1440, 1804}, // 20" x 25 1/16" + "SuperRoyal": {1512, 1944}, // 21" x 27" + "DoublePott": {1080, 1800}, // 15" x 25" + "DoublePost": {1368, 2196}, // 19" x 30 1/2" + "Foolscap": {972, 1224}, // 13 1/2" x 17" + "DoubleFoolscap": {1224, 1944}, // 17" x 27" + + "F4": {595, 935}, // 8 1/4" x 13" + + // GB/T 148-1997 D Series China + "D0": {2166, 3016}, // 29.9" x 41.9" 764 x 1064 mm + "D1": {1508, 2155}, // 20.9" x 29.9" 532 x 760 mm + "D2": {1077, 1497}, // 15.0" x 20.8" 380 x 528 mm + "D3": {748, 1066}, // 10.4" x 14.8" 264 x 376 mm + "D4": {533, 737}, // 7.4" x 10.2" 188 x 260 mm + "D5": {369, 522}, // 5.1" x 7.2" 130 x 184 mm + "D6": {261, 357}, // 3.6" x 5.0" 92 x 126 mm + + "RD0": {2231, 3096}, // 31.0" x 43.0" 787 x 1092 mm + "RD1": {1548, 2231}, // 21.5" x 31.0" 546 x 787 mm + "RD2": {1114, 1548}, // 15.5" x 21.5" 393 x 546 mm + "RD3": {774, 1114}, // 10.7" x 15.5" 273 x 393 mm + "RD4": {556, 774}, // 7.7" x 10.7" 196 x 273 mm + "RD5": {386, 556}, // 5.4" x 7.7" 136 x 196 mm + "RD6": {278, 386}, // 3.9" x 5.4" 98 x 136 mm + + // Japanese B-series variant + "JIS-B0": {2920, 4127}, // 40.55" x 57.32" 1030 x 1456 mm + "JIS-B1": {2064, 2920}, // 28.66" x 40.55" 728 x 1030 mm + "JIS-B2": {1460, 2064}, // 20.28" x 28.66" 515 x 728 mm + "JIS-B3": {1032, 1460}, // 14.33" x 20.28" 364 x 515 mm + "JIS-B4": {729, 1032}, // 10.12" x 14.33" 257 x 364 mm + "JIS-B5": {516, 729}, // 7.17" x 10.12" 182 x 257 mm + "JIS-B6": {363, 516}, // 5.04" x 7.17" 128 x 182 mm + "JIS-B7": {258, 363}, // 3.58" x 5.04" 91 x 128 mm + "JIS-B8": {181, 258}, // 2.52" x 3.58" 64 x 91 mm + "JIS-B9": {127, 181}, // 1.77" x 2.52" 45 x 64 mm + "JIS-B10": {91, 127}, // 1.26" x 1.77" 32 x 45 mm + "JIS-B11": {63, 91}, // 0.87" x 1.26" 22 x 32 mm + "JIS-B12": {45, 63}, // 0.63" x 0.87" 16 x 22 mm + "Shirokuban4": {748, 1074}, // 10.39" x 14.92" 264 x 379 mm + "Shirokuban5": {536, 742}, // 7.44" x 10.31" 189 x 262 mm + "Shirokuban6": {360, 533}, // 5.00" x 7.40" 127 x 188 mm + "Kiku4": {644, 868}, // 8.94" x 12.05" 227 x 306 mm + "Kiku5": {428, 644}, // 5.95" x 8.94" 151 x 227 mm + "AB": {595, 729}, // 8.27" x 10.12" 210 x 257 mm + "B40": {292, 516}, // 4.06" x 7.17" 103 x 182 mm + "Shikisen": {238, 420}, // 3.31" x 5.83" 84 x 148 mm +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parse.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parse.go new file mode 100644 index 0000000..7688344 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parse.go @@ -0,0 +1,1003 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "encoding/hex" + "strconv" + "strings" + "unicode" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +var ( + errArrayCorrupt = errors.New("pdfcpu: parse: corrupt array") + errArrayNotTerminated = errors.New("pdfcpu: parse: unterminated array") + errDictionaryCorrupt = errors.New("pdfcpu: parse: corrupt dictionary") + errDictionaryDuplicateKey = errors.New("pdfcpu: parse: duplicate key") + errDictionaryNotTerminated = errors.New("pdfcpu: parse: unterminated dictionary") + errHexLiteralCorrupt = errors.New("pdfcpu: parse: corrupt hex literal") + errHexLiteralNotTerminated = errors.New("pdfcpu: parse: hex literal not terminated") + errNameObjectCorrupt = errors.New("pdfcpu: parse: corrupt name object") + errNoArray = errors.New("pdfcpu: parse: no array") + errNoDictionary = errors.New("pdfcpu: parse: no dictionary") + errStringLiteralCorrupt = errors.New("pdfcpu: parse: corrupt string literal, possibly unbalanced parenthesis") + errBufNotAvailable = errors.New("pdfcpu: parse: no buffer available") + errXrefStreamMissingW = errors.New("pdfcpu: parse: xref stream dict missing entry W") + errXrefStreamCorruptW = errors.New("pdfcpu: parse: xref stream dict corrupt entry W: expecting array of 3 int") + errXrefStreamCorruptIndex = errors.New("pdfcpu: parse: xref stream dict corrupt entry Index") + errObjStreamMissingN = errors.New("pdfcpu: parse: obj stream dict missing entry W") + errObjStreamMissingFirst = errors.New("pdfcpu: parse: obj stream dict missing entry First") +) + +func positionToNextWhitespace(s string) (int, string) { + + for i, c := range s { + if unicode.IsSpace(c) { + return i, s[i:] + } + } + return 0, s +} + +// PositionToNextWhitespaceOrChar trims a string to next whitespace or one of given chars. +// Returns the index of the position or -1 if no match. +func positionToNextWhitespaceOrChar(s, chars string) (int, string) { + + if len(chars) == 0 { + return positionToNextWhitespace(s) + } + + for i, c := range s { + for _, m := range chars { + if c == m || unicode.IsSpace(c) { + return i, s[i:] + } + } + } + + return -1, s +} + +func positionToNextEOL(s string) string { + + chars := "\x0A\x0D" + + for i, c := range s { + for _, m := range chars { + if c == m { + return s[i:] + } + } + } + return "" +} + +// trimLeftSpace trims leading whitespace and trailing comment. +func trimLeftSpace(s string, relaxed bool) (outstr string, eol bool) { + + log.Parse.Printf("TrimLeftSpace: begin %s\n", s) + + whitespace := func(c rune) bool { return unicode.IsSpace(c) } + + whitespaceNoEol := func(r rune) bool { + switch r { + case '\t', '\v', '\f', ' ', 0x85, 0xA0: + return true + } + return false + } + + outstr = s + + for { + if relaxed { + outstr = strings.TrimLeftFunc(outstr, whitespaceNoEol) + if len(outstr) >= 1 && (outstr[0] == '\n' || outstr[0] == '\r') { + eol = true + } + } + outstr = strings.TrimLeftFunc(outstr, whitespace) + log.Parse.Printf("1 outstr: <%s>\n", outstr) + if len(outstr) <= 1 || outstr[0] != '%' { + break + } + // trim PDF comment (= '%' up to eol) + outstr = positionToNextEOL(outstr) + log.Parse.Printf("2 outstr: <%s>\n", outstr) + + } + + log.Parse.Printf("TrimLeftSpace: end %s\n", outstr) + + return outstr, eol +} + +// HexString validates and formats a hex string to be of even length. +func hexString(s string) (*string, bool) { + if len(s) == 0 { + s1 := "" + return &s1, true + } + + var sb strings.Builder + i := 0 + + for _, c := range strings.ToUpper(s) { + if strings.IndexRune(" \x09\x0A\x0C\x0D", c) >= 0 { + if i%2 > 0 { + sb.WriteString("0") + i = 0 + } + continue + } + isHexChar := false + for _, hexch := range "ABCDEF1234567890" { + if c == hexch { + isHexChar = true + sb.WriteRune(c) + i++ + break + } + } + if !isHexChar { + return nil, false + } + } + + // If the final digit of a hexadecimal string is missing - + // that is, if there is an odd number of digits - the final digit shall be assumed to be 0. + if i%2 > 0 { + sb.WriteString("0") + } + + ss := sb.String() + return &ss, true +} + +// balancedParenthesesPrefix returns the index of the end position of the balanced parentheses prefix of s +// or -1 if unbalanced. s has to start with '(' +func balancedParenthesesPrefix(s string) int { + + var j int + escaped := false + + for i := 0; i < len(s); i++ { + + c := s[i] + + if !escaped && c == '\\' { + escaped = true + continue + } + + if escaped { + escaped = false + continue + } + + if c == '(' { + j++ + } + + if c == ')' { + j-- + } + + if j == 0 { + return i + } + + } + + return -1 +} + +func forwardParseBuf(buf string, pos int) string { + if pos < len(buf) { + return buf[pos:] + } + + return "" +} + +func delimiter(b byte) bool { + + s := "<>[]()/" + + for i := 0; i < len(s); i++ { + if b == s[i] { + return true + } + } + + return false +} + +// parseObjectAttributes parses object number and generation of the next object for given string buffer. +func parseObjectAttributes(line *string) (objectNumber *int, generationNumber *int, err error) { + + log.Parse.Printf("ParseObjectAttributes: buf=<%s>\n", *line) + + if line == nil || len(*line) == 0 { + return nil, nil, errors.New("pdfcpu: ParseObjectAttributes: buf not available") + } + + l := *line + var remainder string + + i := strings.Index(l, "obj") + if i < 0 { + return nil, nil, errors.New("pdfcpu: ParseObjectAttributes: can't find \"obj\"") + } + + remainder = l[i+len("obj"):] + l = l[:i] + + // object number + + l, _ = trimLeftSpace(l, false) + if len(l) == 0 { + return nil, nil, errors.New("pdfcpu: ParseObjectAttributes: can't find object number") + } + + i, _ = positionToNextWhitespaceOrChar(l, "%") + if i <= 0 { + return nil, nil, errors.New("pdfcpu: ParseObjectAttributes: can't find end of object number") + } + + objNr, err := strconv.Atoi(l[:i]) + if err != nil { + return nil, nil, err + } + + // generation number + + l = l[i:] + l, _ = trimLeftSpace(l, false) + if len(l) == 0 { + return nil, nil, errors.New("pdfcpu: ParseObjectAttributes: can't find generation number") + } + + i, _ = positionToNextWhitespaceOrChar(l, "%") + if i <= 0 { + return nil, nil, errors.New("pdfcpu: ParseObjectAttributes: can't find end of generation number") + } + + genNr, err := strconv.Atoi(l[:i]) + if err != nil { + return nil, nil, err + } + + objectNumber = &objNr + generationNumber = &genNr + + *line = remainder + + return objectNumber, generationNumber, nil +} + +func parseArray(line *string) (*Array, error) { + + if line == nil || len(*line) == 0 { + return nil, errNoArray + } + + l := *line + + log.Parse.Printf("ParseArray: %s\n", l) + + if !strings.HasPrefix(l, "[") { + return nil, errArrayCorrupt + } + + if len(l) == 1 { + return nil, errArrayNotTerminated + } + + // position behind '[' + l = forwardParseBuf(l, 1) + + // position to first non whitespace char after '[' + l, _ = trimLeftSpace(l, false) + + if len(l) == 0 { + // only whitespace after '[' + return nil, errArrayNotTerminated + } + + a := Array{} + + for !strings.HasPrefix(l, "]") { + + obj, err := parseObject(&l) + if err != nil { + return nil, err + } + log.Parse.Printf("ParseArray: new array obj=%v\n", obj) + a = append(a, obj) + + // we are positioned on the char behind the last parsed array entry. + if len(l) == 0 { + return nil, errArrayNotTerminated + } + + // position to next non whitespace char. + l, _ = trimLeftSpace(l, false) + if len(l) == 0 { + return nil, errArrayNotTerminated + } + } + + // position behind ']' + l = forwardParseBuf(l, 1) + + *line = l + + log.Parse.Printf("ParseArray: returning array (len=%d): %v\n", len(a), a) + + return &a, nil +} + +func parseStringLiteral(line *string) (Object, error) { + + // Balanced pairs of parenthesis are allowed. + // Empty literals are allowed. + // \ needs special treatment. + // Allowed escape sequences: + // \n x0A + // \r x0D + // \t x09 + // \b x08 + // \f xFF + // \( x28 + // \) x29 + // \\ x5C + // \ddd octal code sequence, d=0..7 + + // Ignore '\' for undefined escape sequences. + + // Unescaped 0x0A,0x0D or combination gets parsed as 0x0A. + + // Join split lines by '\' eol. + + if line == nil || len(*line) == 0 { + return nil, errBufNotAvailable + } + + l := *line + + log.Parse.Printf("parseStringLiteral: begin <%s>\n", l) + + if len(l) < 2 || !strings.HasPrefix(l, "(") { + return nil, errStringLiteralCorrupt + } + + // Calculate prefix with balanced parentheses, + // return index of enclosing ')'. + i := balancedParenthesesPrefix(l) + if i < 0 { + // No balanced parentheses. + return nil, errStringLiteralCorrupt + } + + // remove enclosing '(', ')' + balParStr := l[1:i] + + // Parse string literal, see 7.3.4.2 + //str := stringLiteral(balParStr) + + // position behind ')' + *line = forwardParseBuf(l[i:], 1) + + stringLiteral := StringLiteral(balParStr) + log.Parse.Printf("parseStringLiteral: end <%s>\n", stringLiteral) + + return stringLiteral, nil +} + +func parseHexLiteral(line *string) (Object, error) { + + // hexliterals have no whitespace and can't be empty. + + if line == nil || len(*line) == 0 { + return nil, errBufNotAvailable + } + + l := *line + + log.Parse.Printf("parseHexLiteral: %s\n", l) + + if len(l) < 3 || !strings.HasPrefix(l, "<") { + return nil, errHexLiteralCorrupt + } + + // position behind '<' + l = forwardParseBuf(l, 1) + + eov := strings.Index(l, ">") // end of hex literal. + if eov < 0 { + return nil, errHexLiteralNotTerminated + } + + hexStr, ok := hexString(strings.TrimSpace(l[:eov])) + if !ok { + return nil, errHexLiteralCorrupt + } + + // position behind '>' + *line = forwardParseBuf(l[eov:], 1) + + return HexLiteral(*hexStr), nil +} + +func validateNameHexSequence(s string) error { + + for i := 0; i < len(s); { + c := s[i] + if c != '#' { + i++ + continue + } + + // # detected, next 2 chars have to exist. + if len(s) < i+3 { + return errNameObjectCorrupt + } + + s1 := s[i+1 : i+3] + + // And they have to be hex characters. + _, err := hex.DecodeString(s1) + if err != nil { + return errNameObjectCorrupt + } + + i += 3 + } + + return nil +} + +func parseName(line *string) (*Name, error) { + + // see 7.3.5 + + if line == nil || len(*line) == 0 { + return nil, errBufNotAvailable + } + + l := *line + + log.Parse.Printf("parseNameObject: %s\n", l) + + if len(l) < 2 || !strings.HasPrefix(l, "/") { + return nil, errNameObjectCorrupt + } + + // position behind '/' + l = forwardParseBuf(l, 1) + + // cut off on whitespace or delimiter + eok, _ := positionToNextWhitespaceOrChar(l, "/<>()[]") + if eok < 0 { + // Name terminated by eol. + *line = "" + } else { + *line = l[eok:] + l = l[:eok] + } + + // Validate optional #xx sequences + err := validateNameHexSequence(l) + if err != nil { + return nil, err + } + + nameObj := Name(l) + return &nameObj, nil +} + +func processDictKeys(line *string, relaxed bool) (Dict, error) { + l := *line + eol := false + d := NewDict() + for !strings.HasPrefix(l, ">>") { + key, err := parseName(&l) + if err != nil { + return nil, err + } + log.Parse.Printf("ParseDict: key = %s\n", key) + + // position to first non whitespace after key + l, eol = trimLeftSpace(l, relaxed) + + if len(l) == 0 { + log.Parse.Println("ParseDict: only whitespace after key") + // only whitespace after key + return nil, errDictionaryNotTerminated + } + + // A friendly 🤢 to the devs of the Kdan Pocket Scanner for the iPad. + // Hack for #252: + // For dicts with kv pairs terminated by eol we accept a missing value as an empty string. + if eol { + obj := StringLiteral("") + log.Parse.Printf("ParseDict: dict[%s]=%v\n", key, obj) + if ok := d.Insert(string(*key), obj); !ok { + return nil, errDictionaryDuplicateKey + } + continue + } + + obj, err := parseObject(&l) + if err != nil { + return nil, err + } + + // Specifying the null object as the value of a dictionary entry (7.3.7, "Dictionary Objects") + // shall be equivalent to omitting the entry entirely. + if obj != nil { + log.Parse.Printf("ParseDict: dict[%s]=%v\n", key, obj) + if ok := d.Insert(string(*key), obj); !ok { + return nil, errDictionaryDuplicateKey + } + } + + // we are positioned on the char behind the last parsed dict value. + if len(l) == 0 { + return nil, errDictionaryNotTerminated + } + + // position to next non whitespace char. + l, _ = trimLeftSpace(l, false) + if len(l) == 0 { + return nil, errDictionaryNotTerminated + } + + } + *line = l + return d, nil +} + +func parseDict(line *string, relaxed bool) (Dict, error) { + + if line == nil || len(*line) == 0 { + return nil, errNoDictionary + } + + l := *line + + log.Parse.Printf("ParseDict: %s\n", l) + + if len(l) < 4 || !strings.HasPrefix(l, "<<") { + return nil, errDictionaryCorrupt + } + + // position behind '<<' + l = forwardParseBuf(l, 2) + + // position to first non whitespace char after '<<' + l, _ = trimLeftSpace(l, false) + + if len(l) == 0 { + // only whitespace after '[' + return nil, errDictionaryNotTerminated + } + + d, err := processDictKeys(&l, relaxed) + if err != nil { + return nil, err + } + + // position behind '>>' + l = forwardParseBuf(l, 2) + + *line = l + + log.Parse.Printf("ParseDict: returning dict at: %v\n", d) + + return d, nil +} + +func noBuf(l *string) bool { + return l == nil || len(*l) == 0 +} + +func startParseNumericOrIndRef(l string) (string, string, int) { + i1, _ := positionToNextWhitespaceOrChar(l, "/<([]>") + var l1 string + if i1 > 0 { + l1 = l[i1:] + } else { + l1 = l[len(l):] + } + + str := l + if i1 > 0 { + str = l[:i1] + } + + /* + Integers are sometimes prefixed with any form of 0. + Following is a list of valid prefixes that can be safely ignored: + 0 + 0.000000000 + */ + if len(str) > 1 && str[0] == '0' { + if str[1] == '+' || str[1] == '-' { + str = str[1:] + } else if str[1] == '.' { + var i int + for i = 2; len(str) > i && str[i] == '0'; i++ { + } + if len(str) > i && (str[i] == '+' || str[i] == '-') { + str = str[i:] + } + } + } + return str, l1, i1 +} + +func parseNumericOrIndRef(line *string) (Object, error) { + + if noBuf(line) { + return nil, errBufNotAvailable + } + + l := *line + + // if this object is an integer we need to check for an indirect reference eg. 1 0 R + // otherwise it has to be a float + // we have to check first for integer + str, l1, i1 := startParseNumericOrIndRef(l) + + // Try int + i, err := strconv.Atoi(str) + if err != nil { + + // Try float + f, err := strconv.ParseFloat(str, 64) + if err != nil { + return nil, err + } + + // We have a Float! + log.Parse.Printf("parseNumericOrIndRef: value is numeric float: %f\n", f) + *line = l1 + return Float(f), nil + } + + // We have an Int! + + // if not followed by whitespace return sole integer value. + if i1 <= 0 || delimiter(l[i1]) { + log.Parse.Printf("parseNumericOrIndRef: value is numeric int: %d\n", i) + *line = l1 + return Integer(i), nil + } + + // Must be indirect reference. (123 0 R) + // Missing is the 2nd int and "R". + + iref1 := i + + l = l[i1:] + l, _ = trimLeftSpace(l, false) + if len(l) == 0 { + // only whitespace + *line = l1 + return Integer(i), nil + } + + i2, _ := positionToNextWhitespaceOrChar(l, "/<([]>") + + // if only 2 token, can't be indirect reference. + // if not followed by whitespace return sole integer value. + if i2 <= 0 || delimiter(l[i2]) { + log.Parse.Printf("parseNumericOrIndRef: 2 objects => value is numeric int: %d\n", i) + *line = l1 + return Integer(i), nil + } + + str = l + if i2 > 0 { + str = l[:i2] + } + + iref2, err := strconv.Atoi(str) + if err != nil { + // 2nd int(generation number) not available. + // Can't be an indirect reference. + log.Parse.Printf("parseNumericOrIndRef: 3 objects, 2nd no int, value is no indirect ref but numeric int: %d\n", i) + *line = l1 + return Integer(i), nil + } + + // We have the 2nd int(generation number). + // Look for "R" + + l = l[i2:] + l, _ = trimLeftSpace(l, false) + + if len(l) == 0 { + // only whitespace + l = l1 + return Integer(i), nil + } + + if l[0] == 'R' { + // We have all 3 components to create an indirect reference. + *line = forwardParseBuf(l, 1) + return *NewIndirectRef(iref1, iref2), nil + } + + // 'R' not available. + // Can't be an indirect reference. + log.Parse.Printf("parseNumericOrIndRef: value is no indirect ref(no 'R') but numeric int: %d\n", i) + *line = l1 + + return Integer(i), nil +} + +func parseHexLiteralOrDict(l *string) (val Object, err error) { + + if len(*l) < 2 { + return nil, errBufNotAvailable + } + + // if next char = '<' parseDict. + if (*l)[1] == '<' { + log.Parse.Println("parseHexLiteralOrDict: value = Dictionary") + var ( + d Dict + err error + ) + if d, err = parseDict(l, false); err != nil { + if d, err = parseDict(l, true); err != nil { + return nil, err + } + } + val = d + } else { + // hex literals + log.Parse.Println("parseHexLiteralOrDict: value = Hex Literal") + if val, err = parseHexLiteral(l); err != nil { + return nil, err + } + } + + return val, nil +} + +func parseBooleanOrNull(l string) (val Object, s string, ok bool) { + + // null, absent object + if strings.HasPrefix(l, "null") { + log.Parse.Println("parseBoolean: value = null") + return nil, "null", true + } + + // boolean true + if strings.HasPrefix(l, "true") { + log.Parse.Println("parseBoolean: value = true") + return Boolean(true), "true", true + } + + // boolean false + if strings.HasPrefix(l, "false") { + log.Parse.Println("parseBoolean: value = false") + return Boolean(false), "false", true + } + + return nil, "", false +} + +// parseObject parses next Object from string buffer and returns the updated (left clipped) buffer. +func parseObject(line *string) (Object, error) { + + if noBuf(line) { + return nil, errBufNotAvailable + } + + l := *line + + log.Parse.Printf("ParseObject: buf= <%s>\n", l) + + // position to first non whitespace char + l, _ = trimLeftSpace(l, false) + if len(l) == 0 { + // only whitespace + return nil, errBufNotAvailable + } + + var value Object + var err error + + switch l[0] { + + case '[': // array + log.Parse.Println("ParseObject: value = Array") + a, err := parseArray(&l) + if err != nil { + return nil, err + } + value = *a + + case '/': // name + log.Parse.Println("ParseObject: value = Name Object") + nameObj, err := parseName(&l) + if err != nil { + return nil, err + } + value = *nameObj + + case '<': // hex literal or dict + value, err = parseHexLiteralOrDict(&l) + if err != nil { + return nil, err + } + + case '(': // string literal + log.Parse.Printf("ParseObject: value = String Literal: <%s>\n", l) + if value, err = parseStringLiteral(&l); err != nil { + return nil, err + } + + default: + var valStr string + var ok bool + value, valStr, ok = parseBooleanOrNull(l) + if ok { + l = forwardParseBuf(l, len(valStr)) + break + } + // Must be numeric or indirect reference: + // int 0 r + // int + // float + if value, err = parseNumericOrIndRef(&l); err != nil { + return nil, err + } + + } + + log.Parse.Printf("ParseObject returning %v\n", value) + + *line = l + + return value, nil +} + +// parseXRefStreamDict creates a XRefStreamDict out of a StreamDict. +func parseXRefStreamDict(sd *StreamDict) (*XRefStreamDict, error) { + + log.Parse.Println("ParseXRefStreamDict: begin") + + if sd.Size() == nil { + return nil, errors.New("pdfcpu: ParseXRefStreamDict: \"Size\" not available") + } + + objs := []int{} + + // Read optional parameter Index + indArr := sd.Index() + if indArr != nil { + log.Parse.Println("ParseXRefStreamDict: using index dict") + + //indArr := *pIndArr + if len(indArr)%2 > 1 { + return nil, errXrefStreamCorruptIndex + } + + for i := 0; i < len(indArr)/2; i++ { + + startObj, ok := indArr[i*2].(Integer) + if !ok { + return nil, errXrefStreamCorruptIndex + } + + count, ok := indArr[i*2+1].(Integer) + if !ok { + return nil, errXrefStreamCorruptIndex + } + + for j := 0; j < count.Value(); j++ { + objs = append(objs, startObj.Value()+j) + } + } + + } else { + log.Parse.Println("ParseXRefStreamDict: no index dict") + for i := 0; i < *sd.Size(); i++ { + objs = append(objs, i) + + } + } + + // Read parameter W in order to decode the xref table. + // array of integers representing the size of the fields in a single cross-reference entry. + + var wIntArr [3]int + + a := sd.W() + if a == nil { + return nil, errXrefStreamMissingW + } + + //arr := *w + // validate array with 3 positive integers + if len(a) != 3 { + return nil, errXrefStreamCorruptW + } + + f := func(ok bool, i int) bool { + return !ok || i < 0 + } + + i1, ok := a[0].(Integer) + if f(ok, i1.Value()) { + return nil, errXrefStreamCorruptW + } + wIntArr[0] = int(i1) + + i2, ok := a[1].(Integer) + if f(ok, i2.Value()) { + return nil, errXrefStreamCorruptW + } + wIntArr[1] = int(i2) + + i3, ok := a[2].(Integer) + if f(ok, i3.Value()) { + return nil, errXrefStreamCorruptW + } + wIntArr[2] = int(i3) + + xsd := XRefStreamDict{ + StreamDict: *sd, + Size: *sd.Size(), + Objects: objs, + W: wIntArr, + PreviousOffset: sd.Prev(), + } + + log.Parse.Println("ParseXRefStreamDict: end") + + return &xsd, nil +} + +// objectStreamDict creates a ObjectStreamDict out of a StreamDict. +func objectStreamDict(sd *StreamDict) (*ObjectStreamDict, error) { + + if sd.First() == nil { + return nil, errObjStreamMissingFirst + } + + if sd.N() == nil { + return nil, errObjStreamMissingN + } + + osd := ObjectStreamDict{ + StreamDict: *sd, + ObjCount: *sd.N(), + FirstObjOffset: *sd.First(), + ObjArray: nil} + + return &osd, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parseConfig.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parseConfig.go new file mode 100644 index 0000000..eb00179 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parseConfig.go @@ -0,0 +1,118 @@ +// +build !js + +/* +Copyright 2020 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "io" + "io/ioutil" + + "github.com/pkg/errors" + "gopkg.in/yaml.v2" +) + +type configuration struct { + Reader15 bool `yaml:"reader15"` + DecodeAllStreams bool `yaml:"decodeAllStreams"` + ValidationMode string `yaml:"validationMode"` + Eol string `yaml:"eol"` + WriteObjectStream bool `yaml:"writeObjectStream"` + WriteXRefStream bool `yaml:"writeXRefStream"` + EncryptUsingAES bool `yaml:"encryptUsingAES"` + EncryptKeyLength int `yaml:"encryptKeyLength"` + Permissions int `yaml:"permissions"` + Unit string `yaml:"unit"` + Units string `yaml:"units"` // Be flexible if version < v0.3.8 +} + +func loadedConfig(c configuration, configPath string) *Configuration { + var conf Configuration + conf.Path = configPath + + conf.Reader15 = c.Reader15 + conf.DecodeAllStreams = c.DecodeAllStreams + conf.WriteObjectStream = c.WriteObjectStream + conf.WriteXRefStream = c.WriteXRefStream + conf.EncryptUsingAES = c.EncryptUsingAES + conf.EncryptKeyLength = c.EncryptKeyLength + conf.Permissions = int16(c.Permissions) + + switch c.ValidationMode { + case "ValidationStrict": + conf.ValidationMode = ValidationStrict + case "ValidationRelaxed": + conf.ValidationMode = ValidationRelaxed + case "ValidationNone": + conf.ValidationMode = ValidationNone + } + + switch c.Eol { + case "EolLF": + conf.Eol = EolLF + case "EolCR": + conf.Eol = EolCR + case "EolCRLF": + conf.Eol = EolCRLF + } + + switch c.Unit { + case "points": + conf.Unit = POINTS + case "inches": + conf.Unit = INCHES + case "cm": + conf.Unit = CENTIMETRES + case "mm": + conf.Unit = MILLIMETRES + } + + return &conf +} + +func parseConfigFile(r io.Reader, configPath string) error { + var c configuration + bb, err := ioutil.ReadAll(r) + if err != nil { + return err + } + if err := yaml.Unmarshal(bb, &c); err != nil { + return err + } + + if !MemberOf(c.ValidationMode, []string{"ValidationStrict", "ValidationRelaxed", "ValidationNone"}) { + return errors.Errorf("invalid validationMode: %s", c.ValidationMode) + } + if !MemberOf(c.Eol, []string{"EolLF", "EolCR", "EolCRLF"}) { + return errors.Errorf("invalid eol: %s", c.Eol) + } + if c.Unit == "" { + // v0.3.8 modifies "units" to "unit". + if c.Units != "" { + c.Unit = c.Units + } + } + if !MemberOf(c.Unit, []string{"points", "inches", "cm", "mm"}) { + return errors.Errorf("invalid unit: %s", c.Unit) + } + + if !IntMemberOf(c.EncryptKeyLength, []int{40, 128, 256}) { + return errors.Errorf("encryptKeyLength possible values: 40, 128, 256, got: %s", c.Unit) + } + loadedDefaultConfig = loadedConfig(c, configPath) + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parseConfig_js.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parseConfig_js.go new file mode 100644 index 0000000..e55edc1 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parseConfig_js.go @@ -0,0 +1,209 @@ +/* +Copyright 2020 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bufio" + "io" + "strconv" + "strings" + + "github.com/pkg/errors" +) + +// This gets rid of the gopkg.in/yaml.v2 dependency for wasm builds. + +func handleConfReader15(k, v string, c *Configuration) error { + v = strings.ToLower(v) + if v != "true" && v != "false" { + return errors.Errorf("config key %s is boolean", k) + } + c.Reader15 = v == "true" + return nil +} + +func handleConfDecodeAllStreams(k, v string, c *Configuration) error { + v = strings.ToLower(v) + if v != "true" && v != "false" { + return errors.Errorf("config key %s is boolean", k) + } + c.DecodeAllStreams = v == "true" + return nil +} + +func handleConfValidationMode(v string, c *Configuration) error { + v1 := strings.ToLower(v) + switch v1 { + case "validationstrict": + c.ValidationMode = ValidationStrict + case "validationrelaxed": + c.ValidationMode = ValidationRelaxed + case "validationone": + c.ValidationMode = ValidationNone + default: + return errors.Errorf("invalid validationMode: %s", v) + } + return nil +} + +func handleConfEol(v string, c *Configuration) error { + v1 := strings.ToLower(v) + switch v1 { + case "eollf": + c.Eol = EolLF + case "eolcr": + c.Eol = EolCR + case "eolcrlf": + c.Eol = EolCRLF + default: + return errors.Errorf("invalid eol: %s", v) + } + return nil +} + +func handleConfWriteObjectStream(k, v string, c *Configuration) error { + v = strings.ToLower(v) + if v != "true" && v != "false" { + return errors.Errorf("config key %s is boolean", k) + } + c.WriteObjectStream = v == "true" + return nil +} + +func handleConfWriteXRefStream(k, v string, c *Configuration) error { + v = strings.ToLower(v) + if v != "true" && v != "false" { + return errors.Errorf("config key %s is boolean", k) + } + c.WriteXRefStream = v == "true" + return nil +} + +func handleConfEncryptUsingAES(k, v string, c *Configuration) error { + v = strings.ToLower(v) + if v != "true" && v != "false" { + return errors.Errorf("config key %s is boolean", k) + } + c.EncryptUsingAES = v == "true" + return nil +} + +func handleConfEncryptKeyLength(v string, c *Configuration) error { + i, err := strconv.Atoi(v) + if err != nil { + return errors.Errorf("encryptKeyLength is numeric, got: %s", v) + } + if !IntMemberOf(i, []int{40, 128, 256}) { + return errors.Errorf("encryptKeyLength possible values: 40, 128, 256, got: %s", v) + } + c.EncryptKeyLength = i + return nil +} + +func handleConfPermissions(v string, c *Configuration) error { + i, err := strconv.Atoi(v) + if err != nil { + return errors.Errorf("permissions is numeric, got: %s", v) + } + c.Permissions = int16(i) + return nil +} + +func handleConfUnit(v string, c *Configuration) error { + v1 := v + switch v1 { + case "points": + c.Unit = POINTS + case "inches": + c.Unit = INCHES + case "cm": + c.Unit = CENTIMETRES + case "mm": + c.Unit = MILLIMETRES + default: + return errors.Errorf("invalid unit: %s", v) + } + return nil +} + +func parseKeyValue(k, v string, c *Configuration) error { + var err error + switch k { + case "reader15": + err = handleConfReader15(k, v, c) + + case "decodeAllStreams": + err = handleConfDecodeAllStreams(k, v, c) + + case "validationMode": + err = handleConfValidationMode(v, c) + + case "eol": + err = handleConfEol(v, c) + + case "writeObjectStream": + err = handleConfWriteObjectStream(k, v, c) + + case "writeXRefStream": + err = handleConfWriteXRefStream(k, v, c) + + case "encryptUsingAES": + err = handleConfEncryptUsingAES(k, v, c) + + case "encryptKeyLength": + err = handleConfEncryptKeyLength(v, c) + + case "permissions": + err = handleConfPermissions(v, c) + + case "unit", "units": + err = handleConfUnit(v, c) + } + return err +} + +func parseConfigFile(r io.Reader, configPath string) error { + //fmt.Println("parseConfigFile For JS") + var conf Configuration + conf.Path = configPath + + s := bufio.NewScanner(r) + for s.Scan() { + t := s.Text() + if len(t) == 0 || t[0] == '#' { + continue + } + ss := strings.Split(t, ": ") + if len(ss) != 2 { + return errors.Errorf("invalid entry: <%s>", t) + } + k := strings.TrimSpace(ss[0]) + v := strings.TrimSpace(ss[1]) + if len(k) == 0 || len(v) == 0 { + return errors.Errorf("invalid entry: <%s>", t) + } + if err := parseKeyValue(k, v, &conf); err != nil { + return err + } + } + if err := s.Err(); err != nil { + return err + } + + loadedDefaultConfig = &conf + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parseContent.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parseContent.go new file mode 100644 index 0000000..e48396b --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/parseContent.go @@ -0,0 +1,365 @@ +/* +Copyright 2020 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "strings" + "unicode" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +var ( + errPageContentCorrupt = errors.New("pdfcpu: corrupt page content") + errTJExpressionCorrupt = errors.New("pdfcpu: corrupt TJ expression") + errBIExpressionCorrupt = errors.New("pdfcpu: corrupt BI expression") +) + +func whitespaceOrEOL(c rune) bool { + return unicode.IsSpace(c) || c == 0x0A || c == 0x0D +} + +func skipDict(l *string) error { + s := *l + if !strings.HasPrefix(s, "<<") { + return errDictionaryCorrupt + } + s = s[2:] + j := 0 + for { + i := strings.IndexAny(s, "<>") + if i < 0 { + return errDictionaryCorrupt + } + if s[i] == '<' { + j++ + s = s[i+1:] + continue + } + if s[i] == '>' { + if j > 0 { + j-- + s = s[i+1:] + continue + } + // >> ? + s = s[i:] + if !strings.HasPrefix(s, ">>") { + return errDictionaryCorrupt + } + *l = s[2:] + break + } + } + return nil +} + +func skipStringLiteral(l *string) error { + s := *l + i := 0 + for { + i = strings.IndexByte(s, byte(')')) + if i <= 0 || i > 0 && s[i-1] != '\\' || i > 1 && s[i-2] == '\\' { + break + } + s = s[i+1:] + } + if i < 0 { + return errStringLiteralCorrupt + } + s = s[i+1:] + *l = s + return nil +} + +func skipHexStringLiteral(l *string) error { + s := *l + i := strings.Index(s, ">") + if i < 0 { + return errHexLiteralCorrupt + } + s = s[i+1:] + *l = s + return nil +} + +func skipTJ(l *string) error { + // Each element shall be either a string or a number. + s := *l + for { + s = strings.TrimLeftFunc(s, whitespaceOrEOL) + if s[0] == ']' { + s = s[1:] + break + } + if s[0] == '(' { + if err := skipStringLiteral(&s); err != nil { + return err + } + } + if s[0] == '<' { + if err := skipHexStringLiteral(&s); err != nil { + return err + } + } + i, _ := positionToNextWhitespaceOrChar(s, "<(]") + if i < 0 { + return errTJExpressionCorrupt + } + s = s[i:] + } + *l = s + return nil +} + +func skipBI(l *string, prn PageResourceNames) error { + s := *l + cs := false + for { + s = strings.TrimLeftFunc(s, whitespaceOrEOL) + if strings.HasPrefix(s, "EI") && whitespaceOrEOL(rune(s[2])) { + s = s[2:] + break + } + if s[0] == '/' { + s = s[1:] + i, _ := positionToNextWhitespaceOrChar(s, "/") + if i < 0 { + return errBIExpressionCorrupt + } + n := s[:i] + s = s[i:] + if cs { + if !MemberOf(n, []string{"RGB", "Gray", "CMYK", "DeviceRGB", "DeviceGray", "DeviceCMYK"}) { + prn["ColorSpace"][n] = true + } + cs = false + continue + } + if n == "CS" { + cs = true + } + continue + } + i, _ := positionToNextWhitespaceOrChar(s, "/") + if i < 0 { + return errBIExpressionCorrupt + } + cs = false + s = s[i:] + } + *l = s + return nil +} + +func positionToNextContentToken(line *string, prn PageResourceNames) (bool, error) { + l := *line + for { + l = strings.TrimLeftFunc(l, whitespaceOrEOL) + if len(l) == 0 { + // whitespace or eol only + return true, nil + } + if l[0] == '[' { + // Skip TJ expression: + // [()...()] TJ + // [<>...<>] TJ + if err := skipTJ(&l); err != nil { + return true, err + } + continue + } + if l[0] == '(' { + // Skip text strings as in TJ, Tj, ', " expressions + if err := skipStringLiteral(&l); err != nil { + return true, err + } + continue + } + if l[0] == '<' { + // Skip hex strings as in TJ, Tj, ', " expressions + if err := skipHexStringLiteral(&l); err != nil { + return true, err + } + continue + } + if strings.HasPrefix(l, "BI") && (l[2] == '/' || whitespaceOrEOL(rune(l[2]))) { + // Handle inline image + l = l[2:] + if err := skipBI(&l, prn); err != nil { + return true, err + } + continue + } + *line = l + return false, nil + } +} + +func nextContentToken(line *string, prn PageResourceNames) (string, error) { + // A token is either a name or some chunk terminated by white space or one of /, (, [ + if noBuf(line) { + return "", nil + } + l := *line + t := "" + + //log.Parse.Printf("nextContentToken: start buf= <%s>\n", *line) + + // Skip Tj, TJ and inline images. + done, err := positionToNextContentToken(&l, prn) + if err != nil { + return t, err + } + if done { + return "", nil + } + + if l[0] == '/' { + // Cut off at / [ ( < or white space. + l1 := l[1:] + i, _ := positionToNextWhitespaceOrChar(l1, "/[(<") + if i <= 0 { + *line = "" + return t, errPageContentCorrupt + } + t = l1[:i] + l1 = l1[i:] + l1 = strings.TrimLeftFunc(l1, whitespaceOrEOL) + if !strings.HasPrefix(l1, "<<") { + t = "/" + t + *line = l1 + return t, nil + } + if err := skipDict(&l1); err != nil { + return t, err + } + *line = l1 + return t, nil + } + + i, _ := positionToNextWhitespaceOrChar(l, "/[(<") + if i <= 0 { + *line = "" + return l, nil + } + t = l[:i] + l = l[i:] + if strings.HasPrefix(l, "<<") { + if err := skipDict(&l); err != nil { + return t, err + } + } + *line = l + return t, nil +} + +func resourceNameAtPos1(s, name string, prn PageResourceNames) bool { + switch s { + case "cs", "CS": + if !MemberOf(name, []string{"DeviceGray", "DeviceRGB", "DeviceCMYK", "Pattern"}) { + prn["ColorSpace"][name] = true + log.Parse.Printf("ColorSpace[%s]\n", name) + } + return true + case "gs": + prn["ExtGState"][name] = true + log.Parse.Printf("ExtGState[%s]\n", name) + return true + case "Do": + prn["XObject"][name] = true + log.Parse.Printf("XObject[%s]\n", name) + return true + case "sh": + prn["Shading"][name] = true + log.Parse.Printf("Shading[%s]\n", name) + return true + case "scn", "SCN": + prn["Pattern"][name] = true + log.Parse.Printf("Pattern[%s]\n", name) + return true + case "ri", "BMC", "MP": + return true + } + return false +} + +func resourceNameAtPos2(s, name string, prn PageResourceNames) bool { + switch s { + case "Tf": + prn["Font"][name] = true + log.Parse.Printf("Font[%s]\n", name) + return true + case "BDC", "DP": + prn["Properties"][name] = true + log.Parse.Printf("Properties[%s]\n", name) + return true + } + return false +} + +func parseContent(s string) (PageResourceNames, error) { + var ( + name string + n bool + ) + prn := NewPageResourceNames() + + for pos := 0; ; { + t, err := nextContentToken(&s, prn) + //log.Parse.Printf("t = <%s>\n", t) + if err != nil { + return nil, err + } + if t == "" { + return prn, nil + } + + if t[0] == '/' { + name = t[1:] + if n { + pos++ + } else { + n = true + pos = 0 + } + log.Parse.Printf("name=%s\n", name) + continue + } + + if !n { + log.Parse.Printf("skip:%s\n", t) + continue + } + + pos++ + if pos == 1 { + if resourceNameAtPos1(t, name, prn) { + n = false + } + continue + } + if pos == 2 { + if resourceNameAtPos2(t, name, prn) { + n = false + } + continue + } + return nil, errPageContentCorrupt + } +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/properties.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/properties.go new file mode 100644 index 0000000..1ec4014 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/properties.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + "sort" +) + +// PropertiesList returns a list of document properties as recorded in the document info dict. +func PropertiesList(xRefTable *XRefTable) ([]string, error) { + list := make([]string, 0, len(xRefTable.Properties)) + keys := make([]string, len(xRefTable.Properties)) + i := 0 + for k := range xRefTable.Properties { + keys[i] = k + i++ + } + sort.Strings(keys) + for _, k := range keys { + v := xRefTable.Properties[k] + list = append(list, fmt.Sprintf("%s = %s", k, v)) + } + return list, nil +} + +// PropertiesAdd adds properties into the document info dict. +// Returns true if at least one property was added. +func PropertiesAdd(xRefTable *XRefTable, properties map[string]string) error { + // TODO Handle missing info dict. + d, err := xRefTable.DereferenceDict(*xRefTable.Info) + if err != nil || d == nil { + return err + } + for k, v := range properties { + k1 := UTF8ToCP1252(k) + v1 := UTF8ToCP1252(v) + d[k1] = StringLiteral(v1) + xRefTable.Properties[k1] = v1 + } + return nil +} + +// PropertiesRemove deletes specified properties. +// Returns true if at least one property was removed. +func PropertiesRemove(xRefTable *XRefTable, properties []string) (bool, error) { + // TODO Handle missing info dict. + d, err := xRefTable.DereferenceDict(*xRefTable.Info) + if err != nil || d == nil { + return false, err + } + + if len(properties) == 0 { + // Remove all properties. + for k := range xRefTable.Properties { + k1 := UTF8ToCP1252(k) + delete(d, k1) + } + xRefTable.Properties = map[string]string{} + return true, nil + } + + var removed bool + for _, k := range properties { + k1 := UTF8ToCP1252(k) + _, ok := d[k1] + if ok && !removed { + delete(d, k1) + delete(xRefTable.Properties, k1) + removed = true + } + } + + return removed, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/read.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/read.go new file mode 100644 index 0000000..ec80159 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/read.go @@ -0,0 +1,2579 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bufio" + "bytes" + "io" + "os" + "sort" + "strconv" + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/filter" + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +const ( + defaultBufSize = 1024 +) + +// ReadFile reads in a PDF file and builds an internal structure holding its cross reference table aka the Context. +func ReadFile(inFile string, conf *Configuration) (*Context, error) { + + log.Info.Printf("reading %s..\n", inFile) + + f, err := os.Open(inFile) + if err != nil { + return nil, errors.Wrapf(err, "can't open %q", inFile) + } + + defer func() { + f.Close() + }() + + return Read(f, conf) +} + +// Read takes a readSeeker and generates a Context, +// an in-memory representation containing a cross reference table. +func Read(rs io.ReadSeeker, conf *Configuration) (*Context, error) { + + log.Read.Println("Read: begin") + + ctx, err := NewContext(rs, conf) + if err != nil { + return nil, err + } + + if ctx.Reader15 { + log.Info.Println("PDF Version 1.5 conforming reader") + } else { + log.Info.Println("PDF Version 1.4 conforming reader - no object streams or xrefstreams allowed") + } + + // Populate xRefTable. + if err = readXRefTable(ctx); err != nil { + return nil, errors.Wrap(err, "Read: xRefTable failed") + } + + // Make all objects explicitly available (load into memory) in corresponding xRefTable entries. + // Also decode any involved object streams. + if err = dereferenceXRefTable(ctx, conf); err != nil { + return nil, err + } + + // Some PDFWriters write an incorrect Size into trailer. + if *ctx.XRefTable.Size < len(ctx.XRefTable.Table) { + *ctx.XRefTable.Size = len(ctx.XRefTable.Table) + } + + log.Read.Println("Read: end") + + return ctx, nil +} + +// ScanLines is a split function for a Scanner that returns each line of +// text, stripped of any trailing end-of-line marker. The returned line may +// be empty. The end-of-line marker is one carriage return followed +// by one newline or one carriage return or one newline. +// The last non-empty line of input will be returned even if it has no newline. +func scanLines(data []byte, atEOF bool) (advance int, token []byte, err error) { + + if atEOF && len(data) == 0 { + return 0, nil, nil + } + + indCR := bytes.IndexByte(data, '\r') + indLF := bytes.IndexByte(data, '\n') + + switch { + + case indCR >= 0 && indLF >= 0: + if indCR < indLF { + if indLF == indCR+1 { + // 0x0D0A + return indLF + 1, data[0:indCR], nil + } + // 0x0D ... 0x0A + return indCR + 1, data[0:indCR], nil + } + // 0x0A ... 0x0D + return indLF + 1, data[0:indLF], nil + + case indCR >= 0: + // We have a full carriage return terminated line. + return indCR + 1, data[0:indCR], nil + + case indLF >= 0: + // We have a full newline-terminated line. + return indLF + 1, data[0:indLF], nil + + } + + // If we're at EOF, we have a final, non-terminated line. Return it. + if atEOF { + return len(data), data, nil + } + + // Request more data. + return 0, nil, nil +} + +func newPositionedReader(rs io.ReadSeeker, offset *int64) (*bufio.Reader, error) { + + if _, err := rs.Seek(*offset, io.SeekStart); err != nil { + return nil, err + } + + log.Read.Printf("newPositionedReader: positioned to offset: %d\n", *offset) + + return bufio.NewReader(rs), nil +} + +// Get the file offset of the last XRefSection. +// Go to end of file and search backwards for the first occurrence of startxref {offset} %%EOF +// xref at 114172 +func offsetLastXRefSection(ctx *Context, skip int64) (*int64, error) { + + rs := ctx.Read.rs + + var ( + prevBuf, workBuf []byte + bufSize int64 = 512 + offset int64 + ) + + for i := 1; offset == 0; i++ { + + off, err := rs.Seek(-int64(i)*bufSize-skip, io.SeekEnd) + if err != nil { + return nil, errors.New("pdfcpu: can't find last xref section") + } + + log.Read.Printf("scanning for offsetLastXRefSection starting at %d\n", off) + + curBuf := make([]byte, bufSize) + + _, err = rs.Read(curBuf) + if err != nil { + return nil, err + } + + workBuf = curBuf + if prevBuf != nil { + workBuf = append(curBuf, prevBuf...) + } + + j := strings.LastIndex(string(workBuf), "startxref") + if j == -1 { + prevBuf = curBuf + continue + } + + p := workBuf[j+len("startxref"):] + posEOF := strings.Index(string(p), "%%EOF") + if posEOF == -1 { + return nil, errors.New("pdfcpu: no matching %%EOF for startxref") + } + + p = p[:posEOF] + offset, err = strconv.ParseInt(strings.TrimSpace(string(p)), 10, 64) + if err != nil || offset >= ctx.Read.FileSize { + return nil, errors.New("pdfcpu: corrupted last xref section") + } + } + + log.Read.Printf("Offset last xrefsection: %d\n", offset) + + return &offset, nil +} + +// Read next subsection entry and generate corresponding xref table entry. +func parseXRefTableEntry(s *bufio.Scanner, xRefTable *XRefTable, objectNumber int) error { + + log.Read.Println("parseXRefTableEntry: begin") + + line, err := scanLine(s) + if err != nil { + return err + } + + if xRefTable.Exists(objectNumber) { + log.Read.Printf("parseXRefTableEntry: end - Skip entry %d - already assigned\n", objectNumber) + return nil + } + + fields := strings.Fields(line) + if len(fields) != 3 || + len(fields[0]) != 10 || len(fields[1]) != 5 || len(fields[2]) != 1 { + return errors.New("pdfcpu: parseXRefTableEntry: corrupt xref subsection header") + } + + offset, err := strconv.ParseInt(fields[0], 10, 64) + if err != nil { + return err + } + + generation, err := strconv.Atoi(fields[1]) + if err != nil { + return err + } + + entryType := fields[2] + if entryType != "f" && entryType != "n" { + return errors.New("pdfcpu: parseXRefTableEntry: corrupt xref subsection entry") + } + + var xRefTableEntry XRefTableEntry + + if entryType == "n" { + + // in use object + + log.Read.Printf("parseXRefTableEntry: Object #%d is in use at offset=%d, generation=%d\n", objectNumber, offset, generation) + + if offset == 0 { + log.Info.Printf("parseXRefTableEntry: Skip entry for in use object #%d with offset 0\n", objectNumber) + return nil + } + + xRefTableEntry = + XRefTableEntry{ + Free: false, + Offset: &offset, + Generation: &generation} + + } else { + + // free object + + log.Read.Printf("parseXRefTableEntry: Object #%d is unused, next free is object#%d, generation=%d\n", objectNumber, offset, generation) + + xRefTableEntry = + XRefTableEntry{ + Free: true, + Offset: &offset, + Generation: &generation} + + } + + log.Read.Printf("parseXRefTableEntry: Insert new xreftable entry for Object %d\n", objectNumber) + + xRefTable.Table[objectNumber] = &xRefTableEntry + + log.Read.Println("parseXRefTableEntry: end") + + return nil +} + +// Process xRef table subsection and create corrresponding xRef table entries. +func parseXRefTableSubSection(s *bufio.Scanner, xRefTable *XRefTable, fields []string) error { + + log.Read.Println("parseXRefTableSubSection: begin") + + startObjNumber, err := strconv.Atoi(fields[0]) + if err != nil { + return err + } + + objCount, err := strconv.Atoi(fields[1]) + if err != nil { + return err + } + + log.Read.Printf("detected xref subsection, startObj=%d length=%d\n", startObjNumber, objCount) + + // Process all entries of this subsection into xRefTable entries. + for i := 0; i < objCount; i++ { + if err = parseXRefTableEntry(s, xRefTable, startObjNumber+i); err != nil { + return err + } + } + + log.Read.Println("parseXRefTableSubSection: end") + + return nil +} + +// Parse compressed object. +func compressedObject(s string) (Object, error) { + + log.Read.Println("compressedObject: begin") + + o, err := parseObject(&s) + if err != nil { + return nil, err + } + + d, ok := o.(Dict) + if !ok { + // return trivial Object: Integer, Array, etc. + log.Read.Println("compressedObject: end, any other than dict") + return o, nil + } + + streamLength, streamLengthRef := d.Length() + if streamLength == nil && streamLengthRef == nil { + // return Dict + log.Read.Println("compressedObject: end, dict") + return d, nil + } + + return nil, errors.New("pdfcpu: compressedObject: stream objects are not to be stored in an object stream") +} + +// Parse all objects of an object stream and save them into objectStreamDict.ObjArray. +func parseObjectStream(osd *ObjectStreamDict) error { + + log.Read.Printf("parseObjectStream begin: decoding %d objects.\n", osd.ObjCount) + + decodedContent := osd.Content + prolog := decodedContent[:osd.FirstObjOffset] + + objs := strings.Fields(string(prolog)) + if len(objs)%2 > 0 { + return errors.New("pdfcpu: parseObjectStream: corrupt object stream dict") + } + + // e.g., 10 0 11 25 = 2 Objects: #10 @ offset 0, #11 @ offset 25 + + var objArray Array + + var offsetOld int + + for i := 0; i < len(objs); i += 2 { + + offset, err := strconv.Atoi(objs[i+1]) + if err != nil { + return err + } + + offset += osd.FirstObjOffset + + if i > 0 { + dstr := string(decodedContent[offsetOld:offset]) + log.Read.Printf("parseObjectStream: objString = %s\n", dstr) + o, err := compressedObject(dstr) + if err != nil { + return err + } + + log.Read.Printf("parseObjectStream: [%d] = obj %s:\n%s\n", i/2-1, objs[i-2], o) + objArray = append(objArray, o) + } + + if i == len(objs)-2 { + dstr := string(decodedContent[offset:]) + log.Read.Printf("parseObjectStream: objString = %s\n", dstr) + o, err := compressedObject(dstr) + if err != nil { + return err + } + + log.Read.Printf("parseObjectStream: [%d] = obj %s:\n%s\n", i/2, objs[i], o) + objArray = append(objArray, o) + } + + offsetOld = offset + } + + osd.ObjArray = objArray + + log.Read.Println("parseObjectStream end") + + return nil +} + +// For each object embedded in this xRefStream create the corresponding xRef table entry. +func extractXRefTableEntriesFromXRefStream(buf []byte, xsd *XRefStreamDict, ctx *Context) error { + + log.Read.Printf("extractXRefTableEntriesFromXRefStream begin") + + // Note: + // A value of zero for an element in the W array indicates that the corresponding field shall not be present in the stream, + // and the default value shall be used, if there is one. + // If the first element is zero, the type field shall not be present, and shall default to type 1. + + i1 := xsd.W[0] + i2 := xsd.W[1] + i3 := xsd.W[2] + + xrefEntryLen := i1 + i2 + i3 + log.Read.Printf("extractXRefTableEntriesFromXRefStream: begin xrefEntryLen = %d\n", xrefEntryLen) + + if len(buf)%xrefEntryLen > 0 { + return errors.New("pdfcpu: extractXRefTableEntriesFromXRefStream: corrupt xrefstream") + } + + objCount := len(xsd.Objects) + log.Read.Printf("extractXRefTableEntriesFromXRefStream: objCount:%d %v\n", objCount, xsd.Objects) + + log.Read.Printf("extractXRefTableEntriesFromXRefStream: len(buf):%d objCount*xrefEntryLen:%d\n", len(buf), objCount*xrefEntryLen) + if len(buf) < objCount*xrefEntryLen { + // Sometimes there is an additional xref entry not accounted for by "Index". + // We ignore such a entries and do not treat this as an error. + return errors.New("pdfcpu: extractXRefTableEntriesFromXRefStream: corrupt xrefstream") + } + + j := 0 + + // bufToInt64 interprets the content of buf as an int64. + bufToInt64 := func(buf []byte) (i int64) { + + for _, b := range buf { + i <<= 8 + i |= int64(b) + } + + return + } + + for i := 0; i < len(buf) && j < len(xsd.Objects); i += xrefEntryLen { + + objectNumber := xsd.Objects[j] + + i2Start := i + i1 + c2 := bufToInt64(buf[i2Start : i2Start+i2]) + c3 := bufToInt64(buf[i2Start+i2 : i2Start+i2+i3]) + + var xRefTableEntry XRefTableEntry + + switch buf[i] { + + case 0x00: + // free object + log.Read.Printf("extractXRefTableEntriesFromXRefStream: Object #%d is unused, next free is object#%d, generation=%d\n", objectNumber, c2, c3) + g := int(c3) + + xRefTableEntry = + XRefTableEntry{ + Free: true, + Compressed: false, + Offset: &c2, + Generation: &g} + + case 0x01: + // in use object + log.Read.Printf("extractXRefTableEntriesFromXRefStream: Object #%d is in use at offset=%d, generation=%d\n", objectNumber, c2, c3) + g := int(c3) + + xRefTableEntry = + XRefTableEntry{ + Free: false, + Compressed: false, + Offset: &c2, + Generation: &g} + + case 0x02: + // compressed object + // generation always 0. + log.Read.Printf("extractXRefTableEntriesFromXRefStream: Object #%d is compressed at obj %5d[%d]\n", objectNumber, c2, c3) + objNumberRef := int(c2) + objIndex := int(c3) + + xRefTableEntry = + XRefTableEntry{ + Free: false, + Compressed: true, + ObjectStream: &objNumberRef, + ObjectStreamInd: &objIndex} + + ctx.Read.ObjectStreams[objNumberRef] = true + + } + + if ctx.XRefTable.Exists(objectNumber) { + log.Read.Printf("extractXRefTableEntriesFromXRefStream: Skip entry %d - already assigned\n", objectNumber) + } else { + ctx.Table[objectNumber] = &xRefTableEntry + } + + j++ + } + + log.Read.Println("extractXRefTableEntriesFromXRefStream: end") + + return nil +} + +func xRefStreamDict(ctx *Context, o Object, objNr int, streamOffset int64) (*XRefStreamDict, error) { + + // must be Dict + d, ok := o.(Dict) + if !ok { + return nil, errors.New("pdfcpu: xRefStreamDict: no dict") + } + + // Parse attributes for stream object. + streamLength, streamLengthObjNr := d.Length() + if streamLength == nil && streamLengthObjNr == nil { + return nil, errors.New("pdfcpu: xRefStreamDict: no \"Length\" entry") + } + + filterPipeline, err := pdfFilterPipeline(ctx, d) + if err != nil { + return nil, err + } + + // We have a stream object. + log.Read.Printf("xRefStreamDict: streamobject #%d\n", objNr) + sd := NewStreamDict(d, streamOffset, streamLength, streamLengthObjNr, filterPipeline) + + if _, err = loadEncodedStreamContent(ctx, &sd); err != nil { + return nil, err + } + + // Decode xrefstream content + if err = saveDecodedStreamContent(nil, &sd, 0, 0, true); err != nil { + return nil, errors.Wrapf(err, "xRefStreamDict: cannot decode stream for obj#:%d\n", objNr) + } + + return parseXRefStreamDict(&sd) +} + +// Parse xRef stream and setup xrefTable entries for all embedded objects and the xref stream dict. +func parseXRefStream(rd io.Reader, offset *int64, ctx *Context) (prevOffset *int64, err error) { + + log.Read.Printf("parseXRefStream: begin at offset %d\n", *offset) + + buf, endInd, streamInd, streamOffset, err := buffer(rd) + if err != nil { + return nil, err + } + + log.Read.Printf("parseXRefStream: endInd=%[1]d(%[1]x) streamInd=%[2]d(%[2]x)\n", endInd, streamInd) + + line := string(buf) + + // We expect a stream and therefore "stream" before "endobj" if "endobj" within buffer. + // There is no guarantee that "endobj" is contained in this buffer for large streams! + if streamInd < 0 || (endInd > 0 && endInd < streamInd) { + return nil, errors.New("pdfcpu: parseXRefStream: corrupt pdf file") + } + + // Init object parse buf. + l := line[:streamInd] + + objectNumber, generationNumber, err := parseObjectAttributes(&l) + if err != nil { + return nil, err + } + + // parse this object + log.Read.Printf("parseXRefStream: xrefstm obj#:%d gen:%d\n", *objectNumber, *generationNumber) + log.Read.Printf("parseXRefStream: dereferencing object %d\n", *objectNumber) + o, err := parseObject(&l) + if err != nil { + return nil, errors.Wrapf(err, "parseXRefStream: no object") + } + + log.Read.Printf("parseXRefStream: we have an object: %s\n", o) + + streamOffset += *offset + sd, err := xRefStreamDict(ctx, o, *objectNumber, streamOffset) + if err != nil { + return nil, err + } + // We have an xref stream object + + err = parseTrailerInfo(sd.Dict, ctx.XRefTable) + if err != nil { + return nil, err + } + + // Parse xRefStream and create xRefTable entries for embedded objects. + err = extractXRefTableEntriesFromXRefStream(sd.Content, sd, ctx) + if err != nil { + return nil, err + } + + if ctx.XRefTable.Exists(*objectNumber) { + log.Read.Printf("parseXRefStream: Skip entry %d - already assigned\n", *objectNumber) + } else { + // Create xRefTableEntry for XRefStreamDict. + entry := + XRefTableEntry{ + Free: false, + Offset: offset, + Generation: generationNumber, + Object: *sd} + + log.Read.Printf("parseXRefStream: Insert new xRefTable entry for Object %d\n", *objectNumber) + + ctx.Table[*objectNumber] = &entry + ctx.Read.XRefStreams[*objectNumber] = true + } + prevOffset = sd.PreviousOffset + + log.Read.Println("parseXRefStream: end") + + return prevOffset, nil +} + +// Parse an xRefStream for a hybrid PDF file. +func parseHybridXRefStream(offset *int64, ctx *Context) error { + + log.Read.Println("parseHybridXRefStream: begin") + + rd, err := newPositionedReader(ctx.Read.rs, offset) + if err != nil { + return err + } + + _, err = parseXRefStream(rd, offset, ctx) + if err != nil { + return err + } + + log.Read.Println("parseHybridXRefStream: end") + + return nil +} + +// Parse trailer dict and return any offset of a previous xref section. +func parseTrailerInfo(d Dict, xRefTable *XRefTable) error { + + log.Read.Println("parseTrailerInfo begin") + + if _, found := d.Find("Encrypt"); found { + encryptObjRef := d.IndirectRefEntry("Encrypt") + if encryptObjRef != nil { + xRefTable.Encrypt = encryptObjRef + log.Read.Printf("parseTrailerInfo: Encrypt object: %s\n", *xRefTable.Encrypt) + } + } + + if xRefTable.Size == nil { + size := d.Size() + if size == nil { + return errors.New("pdfcpu: parseTrailerInfo: missing entry \"Size\"") + } + // Not reliable! + // Patched after all read in. + xRefTable.Size = size + } + + if xRefTable.Root == nil { + rootObjRef := d.IndirectRefEntry("Root") + if rootObjRef == nil { + return errors.New("pdfcpu: parseTrailerInfo: missing entry \"Root\"") + } + xRefTable.Root = rootObjRef + log.Read.Printf("parseTrailerInfo: Root object: %s\n", *xRefTable.Root) + } + + if xRefTable.Info == nil { + infoObjRef := d.IndirectRefEntry("Info") + if infoObjRef != nil { + xRefTable.Info = infoObjRef + log.Read.Printf("parseTrailerInfo: Info object: %s\n", *xRefTable.Info) + } + } + + if xRefTable.ID == nil { + idArray := d.ArrayEntry("ID") + if idArray != nil { + xRefTable.ID = idArray + log.Read.Printf("parseTrailerInfo: ID object: %s\n", xRefTable.ID) + } else if xRefTable.Encrypt != nil { + return errors.New("pdfcpu: parseTrailerInfo: missing entry \"ID\"") + } + } + + log.Read.Println("parseTrailerInfo end") + + return nil +} + +func parseTrailerDict(trailerDict Dict, ctx *Context) (*int64, error) { + + log.Read.Println("parseTrailerDict begin") + + xRefTable := ctx.XRefTable + + err := parseTrailerInfo(trailerDict, xRefTable) + if err != nil { + return nil, err + } + + if arr := trailerDict.ArrayEntry("AdditionalStreams"); arr != nil { + log.Read.Printf("parseTrailerInfo: found AdditionalStreams: %s\n", arr) + a := Array{} + for _, value := range arr { + if indRef, ok := value.(IndirectRef); ok { + a = append(a, indRef) + } + } + xRefTable.AdditionalStreams = &a + } + + offset := trailerDict.Prev() + if offset != nil { + log.Read.Printf("parseTrailerDict: previous xref table section offset:%d\n", *offset) + if *offset == 0 { + // Ignoring illegal offset. + log.Read.Println("parseTrailerDict: ignoring previous xref table section") + offset = nil + } + } + + offsetXRefStream := trailerDict.Int64Entry("XRefStm") + if offsetXRefStream == nil { + // No cross reference stream. + if !ctx.Reader15 && xRefTable.Version() >= V14 && !ctx.Read.Hybrid { + return nil, errors.Errorf("parseTrailerDict: PDF1.4 conformant reader: found incompatible version: %s", xRefTable.VersionString()) + } + log.Read.Println("parseTrailerDict end") + // continue to parse previous xref section, if there is any. + return offset, nil + } + + // This file is using cross reference streams. + + if !ctx.Read.Hybrid { + ctx.Read.Hybrid = true + ctx.Read.UsingXRefStreams = true + } + + // 1.5 conformant readers process hidden objects contained + // in XRefStm before continuing to process any previous XRefSection. + // Previous XRefSection is expected to have free entries for hidden entries. + // May appear in XRefSections only. + if ctx.Reader15 { + if err := parseHybridXRefStream(offsetXRefStream, ctx); err != nil { + return nil, err + } + } + + log.Read.Println("parseTrailerDict end") + + return offset, nil +} + +func scanLineRaw(s *bufio.Scanner) (string, error) { + if ok := s.Scan(); !ok { + if s.Err() != nil { + return "", s.Err() + } + return "", errors.New("pdfcpu: scanLineRaw: returning nothing") + } + return s.Text(), nil +} + +func scanLine(s *bufio.Scanner) (s1 string, err error) { + for i := 0; i <= 1; i++ { + s1, err = scanLineRaw(s) + if err != nil { + return "", err + } + if len(s1) > 0 { + break + } + } + + // Remove comment. + i := strings.Index(s1, "%") + if i >= 0 { + s1 = s1[:i] + } + + return s1, nil +} + +func isDict(s string) (bool, error) { + o, err := parseObject(&s) + if err != nil { + return false, err + } + _, ok := o.(Dict) + return ok, nil +} + +func scanTrailerDictStart(s *bufio.Scanner, line *string) error { + l := *line + var err error + for { + i := strings.Index(l, "<<") + if i >= 0 { + *line = l[i:] + return nil + } + l, err = scanLine(s) + log.Read.Printf("line: <%s>\n", l) + if err != nil { + return err + } + } +} + +func scanTrailerDictRemainder(s *bufio.Scanner, line string, buf bytes.Buffer) (string, error) { + var err error + var i, j, k int + + buf.WriteString(line) + buf.WriteString(" ") + log.Read.Printf("scanTrailer dictBuf after start tag: <%s>\n", line) + + line = line[2:] + + for { + + if len(line) == 0 { + line, err = scanLine(s) + if err != nil { + return "", err + } + buf.WriteString(line) + buf.WriteString(" ") + log.Read.Printf("scanTrailer dictBuf next line: <%s>\n", line) + } + + i = strings.Index(line, "<<") + if i < 0 { + // No << + j = strings.Index(line, ">>") + if j >= 0 { + // Yes >> + if k == 0 { + // Check for dict + ok, err := isDict(buf.String()) + if err == nil && ok { + return buf.String(), nil + } + } else { + k-- + } + line = line[j+2:] + continue + } + // No >> + line, err = scanLine(s) + if err != nil { + return "", err + } + buf.WriteString(line) + buf.WriteString(" ") + log.Read.Printf("scanTrailer dictBuf next line: <%s>\n", line) + } else { + // Yes << + j = strings.Index(line, ">>") + if j < 0 { + // No >> + k++ + line = line[i+2:] + } else { + // Yes >> + if i < j { + // handle << + k++ + line = line[i+2:] + } else { + // handle >> + if k == 0 { + // Check for dict + ok, err := isDict(buf.String()) + if err == nil && ok { + return buf.String(), nil + } + } else { + k-- + } + line = line[j+2:] + } + } + } + } +} + +func scanTrailer(s *bufio.Scanner, line string) (string, error) { + var buf bytes.Buffer + log.Read.Printf("line: <%s>\n", line) + + // Scan for dict start tag "<<". + if err := scanTrailerDictStart(s, &line); err != nil { + return "", err + } + + // Scan for dict end tag ">>" but account for inner dicts. + return scanTrailerDictRemainder(s, line, buf) +} + +func processTrailer(ctx *Context, s *bufio.Scanner, line string) (*int64, error) { + var trailerString string + + if line != "trailer" { + trailerString = line[7:] + log.Read.Printf("processTrailer: trailer leftover: <%s>\n", trailerString) + } else { + log.Read.Printf("line (len %d) <%s>\n", len(line), line) + } + + trailerString, err := scanTrailer(s, trailerString) + if err != nil { + return nil, err + } + + log.Read.Printf("processTrailer: trailerString: (len:%d) <%s>\n", len(trailerString), trailerString) + + o, err := parseObject(&trailerString) + if err != nil { + return nil, err + } + + trailerDict, ok := o.(Dict) + if !ok { + return nil, errors.New("pdfcpu: processTrailer: corrupt trailer dict") + } + + log.Read.Printf("processTrailer: trailerDict:\n%s\n", trailerDict) + + return parseTrailerDict(trailerDict, ctx) +} + +// Parse xRef section into corresponding number of xRef table entries. +func parseXRefSection(s *bufio.Scanner, ctx *Context, ssCount *int) (*int64, error) { + log.Read.Println("parseXRefSection begin") + + line, err := scanLine(s) + if err != nil { + return nil, err + } + + log.Read.Printf("parseXRefSection: <%s>\n", line) + + fields := strings.Fields(line) + + // Process all sub sections of this xRef section. + for !strings.HasPrefix(line, "trailer") && len(fields) == 2 { + + if err = parseXRefTableSubSection(s, ctx.XRefTable, fields); err != nil { + return nil, err + } + *ssCount++ + + // trailer or another xref table subsection ? + if line, err = scanLine(s); err != nil { + return nil, err + } + + // if empty line try next line for trailer + if len(line) == 0 { + if line, err = scanLine(s); err != nil { + return nil, err + } + } + + fields = strings.Fields(line) + } + + log.Read.Println("parseXRefSection: All subsections read!") + + if !strings.HasPrefix(line, "trailer") { + return nil, errors.Errorf("xrefsection: missing trailer dict, line = <%s>", line) + } + + log.Read.Println("parseXRefSection: parsing trailer dict..") + + return processTrailer(ctx, s, line) +} + +// Get version from first line of file. +// Beginning with PDF 1.4, the Version entry in the document’s catalog dictionary +// (located via the Root entry in the file’s trailer, as described in 7.5.5, "File Trailer"), +// if present, shall be used instead of the version specified in the Header. +// Save PDF Version from header to xRefTable. +// The header version comes as the first line of the file. +// eolCount is the number of characters used for eol (1 or 2). +func headerVersion(rs io.ReadSeeker) (v *Version, eolCount int, err error) { + log.Read.Println("headerVersion begin") + + var errCorruptHeader = errors.New("pdfcpu: headerVersion: corrupt pdf stream - no header version available") + + // Get first line of file which holds the version of this PDFFile. + // We call this the header version. + if _, err = rs.Seek(0, io.SeekStart); err != nil { + return nil, 0, err + } + + buf := make([]byte, 100) + if _, err = rs.Read(buf); err != nil { + return nil, 0, err + } + + s := string(buf) + prefix := "%PDF-" + + if len(s) < 8 { + return nil, 0, errCorruptHeader + } + + // Allow for leading bytes before %PDF- + i := strings.Index(s, prefix) + if i < 0 { + return nil, 0, errCorruptHeader + } + s = s[i:] + + pdfVersion, err := PDFVersion(s[len(prefix) : len(prefix)+3]) + if err != nil { + return nil, 0, errors.Wrapf(err, "headerVersion: unknown PDF Header Version") + } + + s = s[8:] + s = strings.TrimLeft(s, "\t\f ") + + // Detect the used eol which should be 1 (0x00, 0x0D) or 2 chars (0x0D0A)long. + // %PDF-1.x{whiteSpace}{text}{eol} or + i = strings.IndexAny(s, "\x0A\x0D") + if i < 0 { + return nil, 0, errCorruptHeader + } + if s[i] == 0x0A { + eolCount = 1 + } else if s[i] == 0x0D { + eolCount = 1 + if s[i+1] == 0x0A { + eolCount = 2 + } + } + + log.Read.Printf("headerVersion: end, found header version: %s\n", pdfVersion) + + return &pdfVersion, eolCount, nil +} + +// bypassXrefSection is a hack for digesting corrupt xref sections. +// It populates the xRefTable by reading in all indirect objects line by line +// and works on the assumption of a single xref section - meaning no incremental updates have been made. +func bypassXrefSection(ctx *Context) error { + var z int64 + g := FreeHeadGeneration + ctx.Table[0] = &XRefTableEntry{ + Free: true, + Offset: &z, + Generation: &g} + + rs := ctx.Read.rs + eolCount := ctx.Read.EolCount + var off, offset int64 + + rd, err := newPositionedReader(rs, &offset) + if err != nil { + return err + } + + s := bufio.NewScanner(rd) + s.Split(scanLines) + + bb := []byte{} + var ( + withinObj bool + withinXref bool + withinTrailer bool + ) + + for { + line, err := scanLineRaw(s) + if err != nil { + break + } + if withinXref { + offset += int64(len(line) + eolCount) + if withinTrailer { + bb = append(bb, ' ') + bb = append(bb, line...) + i := strings.Index(line, "startxref") + if i >= 0 { + // Parse trailer. + _, err = processTrailer(ctx, s, string(bb)) + return err + } + continue + } + // Ignore all until "trailer". + i := strings.Index(line, "trailer") + if i >= 0 { + bb = append(bb, line...) + withinTrailer = true + } + continue + } + i := strings.Index(line, "xref") + if i >= 0 { + offset += int64(len(line) + eolCount) + withinXref = true + continue + } + if !withinObj { + i := strings.Index(line, "obj") + if i >= 0 { + withinObj = true + off = offset + bb = append(bb, line[:i+3]...) + } + offset += int64(len(line) + eolCount) + continue + } + + // within obj + offset += int64(len(line) + eolCount) + bb = append(bb, ' ') + bb = append(bb, line...) + i = strings.Index(line, "endobj") + if i >= 0 { + l := string(bb) + objNr, generation, err := parseObjectAttributes(&l) + if err != nil { + return err + } + of := off + ctx.Table[*objNr] = &XRefTableEntry{ + Free: false, + Offset: &of, + Generation: generation} + bb = nil + withinObj = false + } + } + return nil +} + +func postProcess(ctx *Context, xrefSectionCount int) { + // Ensure free object #0 if exactly one xref subsection + // and in one of the following weird situations: + if xrefSectionCount == 1 && !ctx.Exists(0) { + if *ctx.Size == len(ctx.Table)+1 { + // Hack for #262 + // Create free object 0 from scratch if the free list head is missing. + g0 := FreeHeadGeneration + z := int64(0) + ctx.Table[0] = &XRefTableEntry{Free: true, Offset: &z, Generation: &g0} + } else { + // Hack for #250: A friendly 🤢 to the devs of the HP Scanner & Printer software utility. + // Create free object 0 by shifting down all objects by one. + for i := 1; i <= *ctx.Size; i++ { + ctx.Table[i-1] = ctx.Table[i] + } + delete(ctx.Table, *ctx.Size) + } + } +} + +// Build XRefTable by reading XRef streams or XRef sections. +func buildXRefTableStartingAt(ctx *Context, offset *int64) error { + + log.Read.Println("buildXRefTableStartingAt: begin") + + rs := ctx.Read.rs + + hv, eolCount, err := headerVersion(rs) + if err != nil { + return err + } + + ctx.HeaderVersion = hv + ctx.Read.EolCount = eolCount + offs := map[int64]bool{} + xrefSectionCount := 0 + + for offset != nil { + + if offs[*offset] { + offset, err = offsetLastXRefSection(ctx, ctx.Read.FileSize-*offset) + if err != nil { + return err + } + if offs[*offset] { + return nil + } + } + + offs[*offset] = true + rd, err := newPositionedReader(rs, offset) + if err != nil { + return err + } + + s := bufio.NewScanner(rd) + s.Split(scanLines) + + line, err := scanLine(s) + if err != nil { + return err + } + + log.Read.Printf("line: <%s>\n", line) + + if strings.TrimSpace(line) == "xref" { + log.Read.Println("buildXRefTableStartingAt: found xref section") + if offset, err = parseXRefSection(s, ctx, &xrefSectionCount); err != nil { + return err + } + } else { + log.Read.Println("buildXRefTableStartingAt: found xref stream") + ctx.Read.UsingXRefStreams = true + rd, err = newPositionedReader(rs, offset) + if err != nil { + return err + } + if offset, err = parseXRefStream(rd, offset, ctx); err != nil { + log.Read.Printf("bypassXRefSection after %v\n", err) + // Try fix for corrupt single xref section. + return bypassXrefSection(ctx) + } + } + } + + postProcess(ctx, xrefSectionCount) + + log.Read.Println("buildXRefTableStartingAt: end") + + return nil +} + +// Populate the cross reference table for this PDF file. +// Goto offset of first xref table entry. +// Can be "xref" or indirect object reference eg. "34 0 obj" +// Keep digesting xref sections as long as there is a defined previous xref section +// and build up the xref table along the way. +func readXRefTable(ctx *Context) (err error) { + + log.Read.Println("readXRefTable: begin") + + offset, err := offsetLastXRefSection(ctx, 0) + if err != nil { + return + } + + err = buildXRefTableStartingAt(ctx, offset) + if err == io.EOF { + return errors.Wrap(err, "readXRefTable: unexpected eof") + } + if err != nil { + return + } + + //Log list of free objects (not the "free list"). + //log.Read.Printf("freelist: %v\n", ctx.freeObjects()) + + // Ensure valid freelist of objects. + // Note: Acrobat 6.0 and later do not use the free list to recycle object numbers. + err = ctx.EnsureValidFreeList() + if err != nil { + return + } + + log.Read.Println("readXRefTable: end") + + return +} + +func growBufBy(buf []byte, size int, rd io.Reader) ([]byte, error) { + + b := make([]byte, size) + + _, err := rd.Read(b) + if err != nil { + return nil, err + } + //log.Read.Printf("growBufBy: Read %d bytes\n", n) + + return append(buf, b...), nil +} + +func nextStreamOffset(line string, streamInd int) (off int) { + + off = streamInd + len("stream") + + // Skip optional blanks. + // TODO Should be skip optional whitespace instead? + for ; line[off] == 0x20; off++ { + } + + // Skip 0A eol. + if line[off] == '\n' { + off++ + return + } + + // Skip 0D eol. + if line[off] == '\r' { + off++ + // Skip 0D0A eol. + if line[off] == '\n' { + off++ + } + } + + return +} + +func lastStreamMarker(streamInd *int, endInd int, line string) { + + if *streamInd > len(line)-len("stream") { + // No space for another stream marker. + *streamInd = -1 + return + } + + // We start searching after this stream marker. + bufpos := *streamInd + len("stream") + + // Search for next stream marker. + i := strings.Index(line[bufpos:], "stream") + if i < 0 { + // No stream marker within line buffer. + *streamInd = -1 + return + } + + // We found the next stream marker. + *streamInd += len("stream") + i + + if endInd > 0 && *streamInd > endInd { + // We found a stream marker of another object + *streamInd = -1 + } + +} + +// Provide a PDF file buffer of sufficient size for parsing an object w/o stream. +func buffer(rd io.Reader) (buf []byte, endInd int, streamInd int, streamOffset int64, err error) { + + // process: # gen obj ... obj dict ... {stream ... data ... endstream} ... endobj + // streamInd endInd + // -1 if absent -1 if absent + + //log.Read.Println("buffer: begin") + + endInd, streamInd = -1, -1 + + for endInd < 0 && streamInd < 0 { + + buf, err = growBufBy(buf, defaultBufSize, rd) + if err != nil { + return nil, 0, 0, 0, err + } + + line := string(buf) + endInd = strings.Index(line, "endobj") + streamInd = strings.Index(line, "stream") + + if endInd > 0 && (streamInd < 0 || streamInd > endInd) { + // No stream marker in buf detected. + break + } + + // For very rare cases where "stream" also occurs within obj dict + // we need to find the last "stream" marker before a possible end marker. + for streamInd > 0 && !keywordStreamRightAfterEndOfDict(line, streamInd) { + lastStreamMarker(&streamInd, endInd, line) + } + + log.Read.Printf("buffer: endInd=%d streamInd=%d\n", endInd, streamInd) + + if streamInd > 0 { + + // streamOffset ... the offset where the actual stream data begins. + // is right after the eol after "stream". + + slack := 10 // for optional whitespace + eol (max 2 chars) + need := streamInd + len("stream") + slack + + if len(line) < need { + + // to prevent buffer overflow. + buf, err = growBufBy(buf, need-len(line), rd) + if err != nil { + return nil, 0, 0, 0, err + } + + line = string(buf) + } + + streamOffset = int64(nextStreamOffset(line, streamInd)) + } + } + + //log.Read.Printf("buffer: end, returned bufsize=%d streamOffset=%d\n", len(buf), streamOffset) + + return buf, endInd, streamInd, streamOffset, nil +} + +// return true if 'stream' follows end of dict: >>{whitespace}stream +func keywordStreamRightAfterEndOfDict(buf string, streamInd int) bool { + + //log.Read.Println("keywordStreamRightAfterEndOfDict: begin") + + // Get a slice of the chunk right in front of 'stream'. + b := buf[:streamInd] + + // Look for last end of dict marker. + eod := strings.LastIndex(b, ">>") + if eod < 0 { + // No end of dict in buf. + return false + } + + // We found the last >>. Return true if after end of dict only whitespace. + ok := strings.TrimSpace(b[eod:]) == ">>" + + //log.Read.Printf("keywordStreamRightAfterEndOfDict: end, %v\n", ok) + + return ok +} + +func buildFilterPipeline(ctx *Context, filterArray, decodeParmsArr Array, decodeParms Object) ([]PDFFilter, error) { + + var filterPipeline []PDFFilter + + for i, f := range filterArray { + + filterName, ok := f.(Name) + if !ok { + return nil, errors.New("pdfcpu: buildFilterPipeline: filterArray elements corrupt") + } + if decodeParms == nil || decodeParmsArr[i] == nil { + filterPipeline = append(filterPipeline, PDFFilter{Name: filterName.Value(), DecodeParms: nil}) + continue + } + + dict, ok := decodeParmsArr[i].(Dict) + if !ok { + indRef, ok := decodeParmsArr[i].(IndirectRef) + if !ok { + return nil, errors.Errorf("buildFilterPipeline: corrupt Dict: %s\n", dict) + } + d, err := dereferencedDict(ctx, indRef.ObjectNumber.Value()) + if err != nil { + return nil, err + } + dict = d + } + + filterPipeline = append(filterPipeline, PDFFilter{Name: filterName.String(), DecodeParms: dict}) + } + + return filterPipeline, nil +} + +// Return the filter pipeline associated with this stream dict. +func pdfFilterPipeline(ctx *Context, dict Dict) ([]PDFFilter, error) { + + log.Read.Println("pdfFilterPipeline: begin") + + var err error + + o, found := dict.Find("Filter") + if !found { + // stream is not compressed. + return nil, nil + } + + // compressed stream. + + var filterPipeline []PDFFilter + + if indRef, ok := o.(IndirectRef); ok { + o, err = dereferencedObject(ctx, indRef.ObjectNumber.Value()) + if err != nil { + return nil, err + } + } + + //fmt.Printf("dereferenced filter obj: %s\n", obj) + + if name, ok := o.(Name); ok { + + // single filter. + + filterName := name.String() + + o, found := dict.Find("DecodeParms") + if !found { + // w/o decode parameters. + log.Read.Println("pdfFilterPipeline: end w/o decode parms") + return append(filterPipeline, PDFFilter{Name: filterName, DecodeParms: nil}), nil + } + + d, ok := o.(Dict) + if !ok { + ir, ok := o.(IndirectRef) + if !ok { + return nil, errors.Errorf("pdfFilterPipeline: corrupt Dict: %s\n", o) + } + d, err = dereferencedDict(ctx, ir.ObjectNumber.Value()) + if err != nil { + return nil, err + } + } + + // with decode parameters. + log.Read.Println("pdfFilterPipeline: end with decode parms") + return append(filterPipeline, PDFFilter{Name: filterName, DecodeParms: d}), nil + } + + // filter pipeline. + + // Array of filternames + filterArray, ok := o.(Array) + if !ok { + return nil, errors.Errorf("pdfFilterPipeline: Expected filterArray corrupt, %v %T", o, o) + } + + // Optional array of decode parameter dicts. + var decodeParmsArr Array + decodeParms, found := dict.Find("DecodeParms") + if found { + decodeParmsArr, ok = decodeParms.(Array) + if !ok { + return nil, errors.New("pdfcpu: pdfFilterPipeline: expected decodeParms array corrupt") + } + } + + //fmt.Printf("decodeParmsArr: %s\n", decodeParmsArr) + + filterPipeline, err = buildFilterPipeline(ctx, filterArray, decodeParmsArr, decodeParms) + + log.Read.Println("pdfFilterPipeline: end") + + return filterPipeline, err +} + +func streamDictForObject(ctx *Context, d Dict, objNr, streamInd int, streamOffset, offset int64) (sd StreamDict, err error) { + + streamLength, streamLengthRef := d.Length() + + if streamInd <= 0 { + return sd, errors.New("pdfcpu: streamDictForObject: stream object without streamOffset") + } + + filterPipeline, err := pdfFilterPipeline(ctx, d) + if err != nil { + return sd, err + } + + streamOffset += offset + + // We have a stream object. + sd = NewStreamDict(d, streamOffset, streamLength, streamLengthRef, filterPipeline) + + log.Read.Printf("streamDictForObject: end, Streamobject #%d\n", objNr) + + return sd, nil +} + +func dict(ctx *Context, d1 Dict, objNr, genNr, endInd, streamInd int) (d2 Dict, err error) { + + if ctx.EncKey != nil { + _, err := decryptDeepObject(d1, objNr, genNr, ctx.EncKey, ctx.AES4Strings, ctx.E.R) + if err != nil { + return nil, err + } + } + + if endInd >= 0 && (streamInd < 0 || streamInd > endInd) { + log.Read.Printf("dict: end, #%d\n", objNr) + d2 = d1 + } + + return d2, nil +} + +func object(ctx *Context, offset int64, objNr, genNr int) (o Object, endInd, streamInd int, streamOffset int64, err error) { + + var rd io.Reader + rd, err = newPositionedReader(ctx.Read.rs, &offset) + if err != nil { + return nil, 0, 0, 0, err + } + + //log.Read.Printf("object: seeked to offset:%d\n", offset) + + // process: # gen obj ... obj dict ... {stream ... data ... endstream} endobj + // streamInd endInd + // -1 if absent -1 if absent + var buf []byte + buf, endInd, streamInd, streamOffset, err = buffer(rd) + if err != nil { + return nil, 0, 0, 0, err + } + + //log.Read.Printf("streamInd:%d(#%x) streamOffset:%d(#%x) endInd:%d(#%x)\n", streamInd, streamInd, streamOffset, streamOffset, endInd, endInd) + //log.Read.Printf("buflen=%d\n%s", len(buf), hex.Dump(buf)) + + line := string(buf) + + var l string + + if endInd < 0 { // && streamInd >= 0, streamdict + // buf: # gen obj ... obj dict ... stream ... data + // implies we detected no endobj and a stream starting at streamInd. + // big stream, we parse object until "stream" + log.Read.Println("object: big stream, we parse object until stream") + l = line[:streamInd] + } else if streamInd < 0 { // dict + // buf: # gen obj ... obj dict ... endobj + // implies we detected endobj and no stream. + // small object w/o stream, parse until "endobj" + log.Read.Println("object: small object w/o stream, parse until endobj") + l = line[:endInd] + } else if streamInd < endInd { // streamdict + // buf: # gen obj ... obj dict ... stream ... data ... endstream endobj + // implies we detected endobj and stream. + // small stream within buffer, parse until "stream" + log.Read.Println("object: small stream within buffer, parse until stream") + l = line[:streamInd] + } else { // dict + // buf: # gen obj ... obj dict ... endobj # gen obj ... obj dict ... stream + // small obj w/o stream, parse until "endobj" + // stream in buf belongs to subsequent object. + log.Read.Println("object: small obj w/o stream, parse until endobj") + l = line[:endInd] + } + + // Parse object number and object generation. + var objectNr, generationNr *int + objectNr, generationNr, err = parseObjectAttributes(&l) + if err != nil { + return nil, 0, 0, 0, err + } + + if objNr != *objectNr || genNr != *generationNr { + // This is suspicious, but ok if two object numbers point to same offset and only one of them is used + // (compare entry.RefCount) like for cases where the PDF Writer is MS Word 2013. + log.Read.Printf("object %d: non matching objNr(%d) or generationNumber(%d) tags found.\n", objNr, *objectNr, *generationNr) + } + + o, err = parseObject(&l) + + return o, endInd, streamInd, streamOffset, err +} + +// ParseObject parses an object from file at given offset. +func ParseObject(ctx *Context, offset int64, objNr, genNr int) (Object, error) { + + log.Read.Printf("ParseObject: begin, obj#%d, offset:%d\n", objNr, offset) + + obj, endInd, streamInd, streamOffset, err := object(ctx, offset, objNr, genNr) + if err != nil { + return nil, err + } + + switch o := obj.(type) { + + case Dict: + d, err := dict(ctx, o, objNr, genNr, endInd, streamInd) + if err != nil || d != nil { + // Dict + return d, err + } + // StreamDict. + return streamDictForObject(ctx, o, objNr, streamInd, streamOffset, offset) + + case Array: + if ctx.EncKey != nil { + if _, err = decryptDeepObject(o, objNr, genNr, ctx.EncKey, ctx.AES4Strings, ctx.E.R); err != nil { + return nil, err + } + } + return o, nil + + case StringLiteral: + if ctx.EncKey != nil { + s1, err := decryptString(o.Value(), objNr, genNr, ctx.EncKey, ctx.AES4Strings, ctx.E.R) + if err != nil { + return nil, err + } + return StringLiteral(*s1), nil + } + return o, nil + + case HexLiteral: + if ctx.EncKey != nil { + bb, err := decryptHexLiteral(o, objNr, genNr, ctx.EncKey, ctx.AES4Strings, ctx.E.R) + if err != nil { + return nil, err + } + return StringLiteral(string(bb)), nil + } + return o, nil + + default: + return o, nil + } +} + +func dereferencedObject(ctx *Context, objectNumber int) (Object, error) { + + entry, ok := ctx.Find(objectNumber) + if !ok { + return nil, errors.New("pdfcpu: dereferencedObject: unregistered object") + } + + if entry.Compressed { + err := decompressXRefTableEntry(ctx.XRefTable, objectNumber, entry) + if err != nil { + return nil, err + } + } + + if entry.Object == nil { + + log.Read.Printf("dereferencedObject: dereferencing object %d\n", objectNumber) + + o, err := ParseObject(ctx, *entry.Offset, objectNumber, *entry.Generation) + if err != nil { + return nil, errors.Wrapf(err, "dereferencedObject: problem dereferencing object %d", objectNumber) + } + + if o == nil { + return nil, errors.New("pdfcpu: dereferencedObject: object is nil") + } + + entry.Object = o + } + + return entry.Object, nil +} + +func dereferencedInteger(ctx *Context, objectNumber int) (*Integer, error) { + + o, err := dereferencedObject(ctx, objectNumber) + if err != nil { + return nil, err + } + + i, ok := o.(Integer) + if !ok { + return nil, errors.New("pdfcpu: dereferencedInteger: corrupt integer") + } + + return &i, nil +} + +func dereferencedDict(ctx *Context, objectNumber int) (Dict, error) { + + o, err := dereferencedObject(ctx, objectNumber) + if err != nil { + return nil, err + } + + d, ok := o.(Dict) + if !ok { + return nil, errors.New("pdfcpu: dereferencedDict: corrupt dict") + } + + return d, nil +} + +// dereference a Integer object representing an int64 value. +func int64Object(ctx *Context, objectNumber int) (*int64, error) { + + log.Read.Printf("int64Object begin: %d\n", objectNumber) + + i, err := dereferencedInteger(ctx, objectNumber) + if err != nil { + return nil, err + } + + i64 := int64(i.Value()) + + log.Read.Printf("int64Object end: %d\n", objectNumber) + + return &i64, nil + +} + +// Reads and returns a file buffer with length = stream length using provided reader positioned at offset. +func readContentStream(rd io.Reader, streamLength int) ([]byte, error) { + + log.Read.Printf("readContentStream: begin streamLength:%d\n", streamLength) + + buf := make([]byte, streamLength) + + for totalCount := 0; totalCount < streamLength; { + count, err := rd.Read(buf[totalCount:]) + if err != nil { + if err != io.EOF { + return nil, err + } + // Weak heuristic to detect the actual end of this stream + // once we have reached EOF due to incorrect streamLength. + eob := bytes.Index(buf, []byte("endstream")) + if eob < 0 { + return nil, err + } + return buf[:eob], nil + } + + log.Read.Printf("readContentStream: count=%d, buflen=%d(%X)\n", count, len(buf), len(buf)) + totalCount += count + + } + + log.Read.Printf("readContentStream: end\n") + + return buf, nil +} + +// LoadEncodedStreamContent loads the encoded stream content from file into StreamDict. +func loadEncodedStreamContent(ctx *Context, sd *StreamDict) ([]byte, error) { + + log.Read.Printf("LoadEncodedStreamContent: begin\n%v\n", sd) + + var err error + + // Return saved decoded content. + if sd.Raw != nil { + log.Read.Println("LoadEncodedStreamContent: end, already in memory.") + return sd.Raw, nil + } + + // Read stream content encoded at offset with stream length. + + // Dereference stream length if stream length is an indirect object. + if sd.StreamLength == nil { + if sd.StreamLengthObjNr == nil { + return nil, errors.New("pdfcpu: loadEncodedStreamContent: missing streamLength") + } + // Get stream length from indirect object + sd.StreamLength, err = int64Object(ctx, *sd.StreamLengthObjNr) + if err != nil { + return nil, err + } + log.Read.Printf("LoadEncodedStreamContent: new indirect streamLength:%d\n", *sd.StreamLength) + } + + newOffset := sd.StreamOffset + rd, err := newPositionedReader(ctx.Read.rs, &newOffset) + if err != nil { + return nil, err + } + + log.Read.Printf("LoadEncodedStreamContent: seeked to offset:%d\n", newOffset) + + // Buffer stream contents. + // Read content from disk. + rawContent, err := readContentStream(rd, int(*sd.StreamLength)) + if err != nil { + return nil, err + } + + // Sometimes the stream dict length is corrupt and needs to be fixed. + l := int64(len(rawContent)) + if l < *sd.StreamLength { + sd.StreamLength = &l + sd.Dict["Length"] = Integer(l) + } + + //log.Read.Printf("rawContent buflen=%d(#%x)\n%s", len(rawContent), len(rawContent), hex.Dump(rawContent)) + + // Save encoded content. + sd.Raw = rawContent + + log.Read.Printf("LoadEncodedStreamContent: end: len(streamDictRaw)=%d\n", len(sd.Raw)) + + // Return encoded content. + return rawContent, nil +} + +// Decodes the raw encoded stream content and saves it to streamDict.Content. +func saveDecodedStreamContent(ctx *Context, sd *StreamDict, objNr, genNr int, decode bool) (err error) { + + log.Read.Printf("saveDecodedStreamContent: begin decode=%t\n", decode) + + // If the "Identity" crypt filter is used we do not need to decrypt. + if ctx != nil && ctx.EncKey != nil { + if len(sd.FilterPipeline) == 1 && sd.FilterPipeline[0].Name == "Crypt" { + sd.Content = sd.Raw + return nil + } + } + + // Special case: If the length of the encoded data is 0, we do not need to decode anything. + if len(sd.Raw) == 0 { + sd.Content = sd.Raw + return nil + } + + // ctx gets created after XRefStream parsing. + // XRefStreams are not encrypted. + if ctx != nil && ctx.EncKey != nil { + sd.Raw, err = decryptStream(sd.Raw, objNr, genNr, ctx.EncKey, ctx.AES4Streams, ctx.E.R) + if err != nil { + return err + } + l := int64(len(sd.Raw)) + sd.StreamLength = &l + } + + if !decode { + return nil + } + + // Actual decoding of content stream. + err = sd.Decode() + if err == filter.ErrUnsupportedFilter { + err = nil + } + if err != nil { + return err + } + + log.Read.Println("saveDecodedStreamContent: end") + + return nil +} + +// Resolve compressed xRefTableEntry +func decompressXRefTableEntry(xRefTable *XRefTable, objectNumber int, entry *XRefTableEntry) error { + + log.Read.Printf("decompressXRefTableEntry: compressed object %d at %d[%d]\n", objectNumber, *entry.ObjectStream, *entry.ObjectStreamInd) + + // Resolve xRefTable entry of referenced object stream. + objectStreamXRefTableEntry, ok := xRefTable.Find(*entry.ObjectStream) + if !ok { + return errors.Errorf("decompressXRefTableEntry: problem dereferencing object stream %d, no xref table entry", *entry.ObjectStream) + } + + // Object of this entry has to be a ObjectStreamDict. + sd, ok := objectStreamXRefTableEntry.Object.(ObjectStreamDict) + if !ok { + return errors.Errorf("decompressXRefTableEntry: problem dereferencing object stream %d, no object stream", *entry.ObjectStream) + } + + // Get indexed object from ObjectStreamDict. + o, err := sd.IndexedObject(*entry.ObjectStreamInd) + if err != nil { + return errors.Wrapf(err, "decompressXRefTableEntry: problem dereferencing object stream %d", *entry.ObjectStream) + } + + // Save object to XRefRableEntry. + g := 0 + entry.Object = o + entry.Generation = &g + entry.Compressed = false + + log.Read.Printf("decompressXRefTableEntry: end, Obj %d[%d]:\n<%s>\n", *entry.ObjectStream, *entry.ObjectStreamInd, o) + + return nil +} + +// Log interesting stream content. +func logStream(o Object) { + + switch o := o.(type) { + + case StreamDict: + + if o.Content == nil { + log.Read.Println("logStream: no stream content") + } + + if o.IsPageContent { + //log.Read.Printf("content <%s>\n", StreamDict.Content) + } + + case ObjectStreamDict: + + if o.Content == nil { + log.Read.Println("logStream: no object stream content") + } else { + log.Read.Printf("logStream: objectStream content = %s\n", o.Content) + } + + if o.ObjArray == nil { + log.Read.Println("logStream: no object stream obj arr") + } else { + log.Read.Printf("logStream: objectStream objArr = %s\n", o.ObjArray) + } + + default: + log.Read.Println("logStream: no ObjectStreamDict") + + } + +} + +// Decode all object streams so contained objects are ready to be used. +func decodeObjectStreams(ctx *Context) error { + + // Note: + // Entry "Extends" intentionally left out. + // No object stream collection validation necessary. + + log.Read.Println("decodeObjectStreams: begin") + + // Get sorted slice of object numbers. + var keys []int + for k := range ctx.Read.ObjectStreams { + keys = append(keys, k) + } + sort.Ints(keys) + + for _, objectNumber := range keys { + + // Get XRefTableEntry. + entry := ctx.XRefTable.Table[objectNumber] + if entry == nil { + return errors.Errorf("decodeObjectStream: missing entry for obj#%d\n", objectNumber) + } + + log.Read.Printf("decodeObjectStreams: parsing object stream for obj#%d\n", objectNumber) + + // Parse object stream from file. + o, err := ParseObject(ctx, *entry.Offset, objectNumber, *entry.Generation) + if err != nil || o == nil { + return errors.New("pdfcpu: decodeObjectStreams: corrupt object stream") + } + + // Ensure StreamDict + sd, ok := o.(StreamDict) + if !ok { + return errors.New("pdfcpu: decodeObjectStreams: corrupt object stream") + } + + // Load encoded stream content to xRefTable. + if _, err = loadEncodedStreamContent(ctx, &sd); err != nil { + return errors.Wrapf(err, "decodeObjectStreams: problem dereferencing object stream %d", objectNumber) + } + + // Save decoded stream content to xRefTable. + if err = saveDecodedStreamContent(ctx, &sd, objectNumber, *entry.Generation, true); err != nil { + log.Read.Printf("obj %d: %s", objectNumber, err) + return err + } + + // Ensure decoded objectArray for object stream dicts. + if !sd.IsObjStm() { + return errors.New("pdfcpu: decodeObjectStreams: corrupt object stream") + } + + // We have an object stream. + log.Read.Printf("decodeObjectStreams: object stream #%d\n", objectNumber) + + ctx.Read.UsingObjectStreams = true + + // Create new object stream dict. + osd, err := objectStreamDict(&sd) + if err != nil { + return errors.Wrapf(err, "decodeObjectStreams: problem dereferencing object stream %d", objectNumber) + } + + log.Read.Printf("decodeObjectStreams: decoding object stream %d:\n", objectNumber) + + // Parse all objects of this object stream and save them to ObjectStreamDict.ObjArray. + if err = parseObjectStream(osd); err != nil { + return errors.Wrapf(err, "decodeObjectStreams: problem decoding object stream %d\n", objectNumber) + } + + if osd.ObjArray == nil { + return errors.Wrap(err, "decodeObjectStreams: objArray should be set!") + } + + log.Read.Printf("decodeObjectStreams: decoded object stream %d:\n", objectNumber) + + // Save object stream dict to xRefTableEntry. + entry.Object = *osd + } + + log.Read.Println("decodeObjectStreams: end") + + return nil +} + +func handleLinearizationParmDict(ctx *Context, obj Object, objNr int) error { + + if ctx.Read.Linearized { + // Linearization dict already processed. + return nil + } + + // handle linearization parm dict. + if d, ok := obj.(Dict); ok && d.IsLinearizationParmDict() { + + ctx.Read.Linearized = true + ctx.LinearizationObjs[objNr] = true + log.Read.Printf("handleLinearizationParmDict: identified linearizationObj #%d\n", objNr) + + a := d.ArrayEntry("H") + + if a == nil { + return errors.Errorf("handleLinearizationParmDict: corrupt linearization dict at obj:%d - missing array entry H", objNr) + } + + if len(a) != 2 && len(a) != 4 { + return errors.Errorf("handleLinearizationParmDict: corrupt linearization dict at obj:%d - corrupt array entry H, needs length 2 or 4", objNr) + } + + offset, ok := a[0].(Integer) + if !ok { + return errors.Errorf("handleLinearizationParmDict: corrupt linearization dict at obj:%d - corrupt array entry H, needs Integer values", objNr) + } + + offset64 := int64(offset.Value()) + ctx.OffsetPrimaryHintTable = &offset64 + + if len(a) == 4 { + + offset, ok := a[2].(Integer) + if !ok { + return errors.Errorf("handleLinearizationParmDict: corrupt linearization dict at obj:%d - corrupt array entry H, needs Integer values", objNr) + } + + offset64 := int64(offset.Value()) + ctx.OffsetOverflowHintTable = &offset64 + } + } + + return nil +} + +func loadStreamDict(ctx *Context, sd *StreamDict, objNr, genNr int) error { + + var err error + + // Load encoded stream content for stream dicts into xRefTable entry. + if _, err = loadEncodedStreamContent(ctx, sd); err != nil { + return errors.Wrapf(err, "dereferenceObject: problem dereferencing stream %d", objNr) + } + + ctx.Read.BinaryTotalSize += *sd.StreamLength + + // Decode stream content. + err = saveDecodedStreamContent(ctx, sd, objNr, genNr, ctx.DecodeAllStreams) + + return err +} + +func updateBinaryTotalSize(ctx *Context, o Object) { + + switch o := o.(type) { + + case StreamDict: + ctx.Read.BinaryTotalSize += *o.StreamLength + + case ObjectStreamDict: + ctx.Read.BinaryTotalSize += *o.StreamLength + + case XRefStreamDict: + ctx.Read.BinaryTotalSize += *o.StreamLength + + } + +} + +func dereferenceObject(ctx *Context, objNr int) error { + + xRefTable := ctx.XRefTable + xRefTableSize := len(xRefTable.Table) + + log.Read.Printf("dereferenceObject: begin, dereferencing object %d\n", objNr) + + entry := xRefTable.Table[objNr] + + if entry.Free { + log.Read.Printf("free object %d\n", objNr) + return nil + } + + if entry.Compressed { + err := decompressXRefTableEntry(xRefTable, objNr, entry) + if err != nil { + return err + } + //log.Read.Printf("dereferenceObject: decompressed entry, Compressed=%v\n%s\n", entry.Compressed, entry.Object) + return nil + } + + // entry is in use. + log.Read.Printf("in use object %d\n", objNr) + + if entry.Offset == nil || *entry.Offset == 0 { + log.Read.Printf("dereferenceObject: already decompressed or used object w/o offset -> ignored") + return nil + } + + o := entry.Object + + // Already dereferenced stream dict. + if o != nil { + logStream(entry.Object) + updateBinaryTotalSize(ctx, o) + log.Read.Printf("handleCachedStreamDict: using cached object %d of %d\n<%s>\n", objNr, xRefTableSize, entry.Object) + return nil + } + + // Dereference (load from disk into memory). + + log.Read.Printf("dereferenceObject: dereferencing object %d\n", objNr) + + // Parse object from file: anything goes dict, array, integer, float, streamdicts... + o, err := ParseObject(ctx, *entry.Offset, objNr, *entry.Generation) + if err != nil { + return errors.Wrapf(err, "dereferenceObject: problem dereferencing object %d", objNr) + } + + entry.Object = o + + // Linearization dicts are validated and recorded for stats only. + err = handleLinearizationParmDict(ctx, o, objNr) + if err != nil { + return err + } + + // Handle stream dicts. + + if _, ok := o.(ObjectStreamDict); ok { + return errors.Errorf("dereferenceObject: object stream should already be dereferenced at obj:%d", objNr) + } + + if _, ok := o.(XRefStreamDict); ok { + return errors.Errorf("dereferenceObject: xref stream should already be dereferenced at obj:%d", objNr) + } + + if sd, ok := o.(StreamDict); ok { + + err = loadStreamDict(ctx, &sd, objNr, *entry.Generation) + if err != nil { + return err + } + + entry.Object = sd + } + + log.Read.Printf("dereferenceObject: end obj %d of %d\n<%s>\n", objNr, xRefTableSize, entry.Object) + + logStream(entry.Object) + + return nil +} + +func processDictRefCounts(xRefTable *XRefTable, d Dict) { + for _, e := range d { + switch o1 := e.(type) { + case IndirectRef: + entry, ok := xRefTable.FindTableEntryForIndRef(&o1) + if ok { + entry.RefCount++ + } + case Dict: + processRefCounts(xRefTable, o1) + case Array: + processRefCounts(xRefTable, o1) + } + } +} + +func processArrayRefCounts(xRefTable *XRefTable, a Array) { + for _, e := range a { + switch o1 := e.(type) { + case IndirectRef: + entry, ok := xRefTable.FindTableEntryForIndRef(&o1) + if ok { + entry.RefCount++ + } + case Dict: + processRefCounts(xRefTable, o1) + case Array: + processRefCounts(xRefTable, o1) + } + } +} + +func processRefCounts(xRefTable *XRefTable, o Object) { + + switch o := o.(type) { + case Dict: + processDictRefCounts(xRefTable, o) + + case StreamDict: + processDictRefCounts(xRefTable, o.Dict) + + case Array: + processArrayRefCounts(xRefTable, o) + } +} + +// Dereferences all objects including compressed objects from object streams. +func dereferenceObjects(ctx *Context) error { + + log.Read.Println("dereferenceObjects: begin") + + xRefTable := ctx.XRefTable + + // Get sorted slice of object numbers. + // TODO Skip sorting for performance gain. + var keys []int + for k := range xRefTable.Table { + keys = append(keys, k) + } + sort.Ints(keys) + + for _, objNr := range keys { + err := dereferenceObject(ctx, objNr) + if err != nil { + return err + } + } + + for _, objNr := range keys { + entry := xRefTable.Table[objNr] + if entry.Free || entry.Compressed { + continue + } + processRefCounts(xRefTable, entry.Object) + } + + log.Read.Println("dereferenceObjects: end") + + return nil +} + +// Locate a possible Version entry (since V1.4) in the catalog +// and record this as rootVersion (as opposed to headerVersion). +func identifyRootVersion(xRefTable *XRefTable) error { + + log.Read.Println("identifyRootVersion: begin") + + // Try to get Version from Root. + rootVersionStr, err := xRefTable.ParseRootVersion() + if err != nil { + return err + } + + if rootVersionStr == nil { + return nil + } + + // Validate version and save corresponding constant to xRefTable. + rootVersion, err := PDFVersion(*rootVersionStr) + if err != nil { + return errors.Wrapf(err, "identifyRootVersion: unknown PDF Root version: %s\n", *rootVersionStr) + } + + xRefTable.RootVersion = &rootVersion + + // since V1.4 the header version may be overridden by a Version entry in the catalog. + if *xRefTable.HeaderVersion < V14 { + log.Info.Printf("identifyRootVersion: PDF version is %s - will ignore root version: %s\n", + xRefTable.HeaderVersion, *rootVersionStr) + } + + log.Read.Println("identifyRootVersion: end") + + return nil +} + +// Parse all Objects including stream content from file and save to the corresponding xRefTableEntries. +// This includes processing of object streams and linearization dicts. +func dereferenceXRefTable(ctx *Context, conf *Configuration) error { + + log.Read.Println("dereferenceXRefTable: begin") + + xRefTable := ctx.XRefTable + + // Note for encrypted files: + // Mandatory provide userpw to open & display file. + // Access may be restricted (Decode access privileges). + // Optionally provide ownerpw in order to gain unrestricted access. + err := checkForEncryption(ctx) + if err != nil { + return err + } + //fmt.Println("pw authenticated") + + // Prepare decompressed objects. + err = decodeObjectStreams(ctx) + if err != nil { + return err + } + + // For each xRefTableEntry assign a Object either by parsing from file or pointing to a decompressed object. + err = dereferenceObjects(ctx) + if err != nil { + return err + } + + // Identify an optional Version entry in the root object/catalog. + err = identifyRootVersion(xRefTable) + if err != nil { + return err + } + + log.Read.Println("dereferenceXRefTable: end") + + return nil +} + +func handleUnencryptedFile(ctx *Context) error { + + if ctx.Cmd == DECRYPT || ctx.Cmd == SETPERMISSIONS { + return errors.New("pdfcpu: this file is not encrypted") + } + + if ctx.Cmd != ENCRYPT { + return nil + } + + // Encrypt subcommand found. + + if ctx.OwnerPW == "" { + return errors.New("pdfcpu: please provide owner password and optional user password") + } + + return nil +} + +func idBytes(ctx *Context) (id []byte, err error) { + + if ctx.ID == nil { + return nil, errors.New("pdfcpu: missing ID entry") + } + + hl, ok := ctx.ID[0].(HexLiteral) + if ok { + id, err = hl.Bytes() + if err != nil { + return nil, err + } + } else { + sl, ok := ctx.ID[0].(StringLiteral) + if !ok { + return nil, errors.New("pdfcpu: ID must contain hex literals or string literals") + } + id, err = Unescape(sl.Value()) + if err != nil { + return nil, err + } + } + + return id, nil +} + +func needsOwnerAndUserPassword(cmd CommandMode) bool { + + return cmd == CHANGEOPW || cmd == CHANGEUPW || cmd == SETPERMISSIONS +} + +func handlePermissions(ctx *Context) error { + + // AES256 Validate permissions + ok, err := validatePermissions(ctx) + if err != nil { + return err + } + + if !ok { + return errors.New("pdfcpu: corrupted permissions after upw ok") + } + + // Double check minimum permissions for pdfcpu processing. + if !hasNeededPermissions(ctx.Cmd, ctx.E) { + return errors.New("pdfcpu: insufficient access permissions") + } + + return nil +} + +func setupEncryptionKey(ctx *Context, d Dict) (err error) { + + ctx.E, err = supportedEncryption(ctx, d) + if err != nil { + return err + } + + ctx.E.ID, err = idBytes(ctx) + if err != nil { + return err + } + + var ok bool + + //fmt.Printf("opw: <%s> upw: <%s> \n", ctx.OwnerPW, ctx.UserPW) + + // Validate the owner password aka. permissions/master password. + ok, err = validateOwnerPassword(ctx) + if err != nil { + return err + } + + // If the owner password does not match we generally move on if the user password is correct + // unless we need to insist on a correct owner password due to the specific command in progress. + if !ok && needsOwnerAndUserPassword(ctx.Cmd) { + return errors.New("pdfcpu: please provide the owner password with -opw") + } + + // Generally the owner password, which is also regarded as the master password or set permissions password + // is sufficient for moving on. A password change is an exception since it requires both current passwords. + if ok && !needsOwnerAndUserPassword(ctx.Cmd) { + // AES256 Validate permissions + ok, err = validatePermissions(ctx) + if err != nil { + return err + } + if !ok { + return errors.New("pdfcpu: corrupted permissions after opw ok") + } + return nil + } + + // Validate the user password aka. document open password. + ok, err = validateUserPassword(ctx) + if err != nil { + return err + } + if !ok { + return errors.New("pdfcpu: please provide the correct password") + } + + //fmt.Printf("upw ok: %t\n", ok) + + return handlePermissions(ctx) +} + +func checkForEncryption(ctx *Context) error { + + ir := ctx.Encrypt + + if ir == nil { + // This file is not encrypted. + return handleUnencryptedFile(ctx) + } + + // This file is encrypted. + log.Read.Printf("Encryption: %v\n", ir) + + if ctx.Cmd == ENCRYPT { + // We want to encrypt this file. + return errors.New("pdfcpu: this file is already encrypted") + } + + // Dereference encryptDict. + d, err := dereferencedDict(ctx, ir.ObjectNumber.Value()) + if err != nil { + return err + } + log.Read.Printf("%s\n", d) + + // We need to decrypt this file in order to read it. + return setupEncryptionKey(ctx, d) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/readImage.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/readImage.go new file mode 100644 index 0000000..88c1ef9 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/readImage.go @@ -0,0 +1,399 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "image" + "image/color" + "image/draw" + _ "image/jpeg" + _ "image/png" + + "github.com/pdfcpu/pdfcpu/pkg/filter" + "github.com/pkg/errors" +) + +func createSMaskObject(xRefTable *XRefTable, buf []byte, w, h, bpc int) (*IndirectRef, error) { + sd := &StreamDict{ + Dict: Dict( + map[string]Object{ + "Type": Name("XObject"), + "Subtype": Name("Image"), + "BitsPerComponent": Integer(bpc), + "ColorSpace": Name(DeviceGrayCS), + "Width": Integer(w), + "Height": Integer(h), + }, + ), + Content: buf, + FilterPipeline: []PDFFilter{{Name: filter.Flate, DecodeParms: nil}}, + } + + sd.InsertName("Filter", filter.Flate) + + if err := sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +func createFlateImageObject(xRefTable *XRefTable, buf, sm []byte, w, h, bpc int, cs string) (*StreamDict, error) { + var softMaskIndRef *IndirectRef + + if sm != nil { + var err error + softMaskIndRef, err = createSMaskObject(xRefTable, sm, w, h, bpc) + if err != nil { + return nil, err + } + } + + sd, _ := xRefTable.NewStreamDictForBuf(buf) + sd.InsertName("Type", "XObject") + sd.InsertName("Subtype", "Image") + sd.InsertInt("Width", w) + sd.InsertInt("Height", h) + sd.InsertInt("BitsPerComponent", bpc) + sd.InsertName("ColorSpace", cs) + + if softMaskIndRef != nil { + sd.Insert("SMask", *softMaskIndRef) + } + + if w < 1000 || h < 1000 { + sd.Insert("Interpolate", Boolean(true)) + } + + if err := sd.Encode(); err != nil { + return nil, err + } + + return sd, nil +} + +func createDCTImageObject(xRefTable *XRefTable, buf []byte, w, h int, cs string) (*StreamDict, error) { + sd := &StreamDict{ + Dict: Dict( + map[string]Object{ + "Type": Name("XObject"), + "Subtype": Name("Image"), + "Width": Integer(w), + "Height": Integer(h), + "BitsPerComponent": Integer(8), + "ColorSpace": Name(cs), + }, + ), + Content: buf, + FilterPipeline: nil, + } + + if cs == DeviceCMYKCS { + sd.Insert("Decode", NewIntegerArray(1, 0, 1, 0, 1, 0, 1, 0)) + } + + if w < 1000 || h < 1000 { + sd.Insert("Interpolate", Boolean(true)) + } + + sd.InsertName("Filter", filter.DCT) + + if err := sd.Encode(); err != nil { + return nil, err + } + + sd.FilterPipeline = []PDFFilter{{Name: filter.DCT, DecodeParms: nil}} + + return sd, nil +} + +func writeRGBAImageBuf(img image.Image) []byte { + w := img.Bounds().Dx() + h := img.Bounds().Dy() + i := 0 + buf := make([]byte, w*h*3) + + for y := 0; y < h; y++ { + for x := 0; x < w; x++ { + c := img.At(x, y).(color.RGBA) + buf[i] = c.R + buf[i+1] = c.G + buf[i+2] = c.B + i += 3 + } + } + + return buf +} + +func writeRGBA64ImageBuf(img image.Image) []byte { + w := img.Bounds().Dx() + h := img.Bounds().Dy() + i := 0 + buf := make([]byte, w*h*6) + + for y := 0; y < h; y++ { + for x := 0; x < w; x++ { + c := img.At(x, y).(color.RGBA64) + buf[i] = uint8(c.R >> 8) + buf[i+1] = uint8(c.R & 0x00FF) + buf[i+2] = uint8(c.G >> 8) + buf[i+3] = uint8(c.G & 0x00FF) + buf[i+4] = uint8(c.B >> 8) + buf[i+5] = uint8(c.B & 0x00FF) + i += 6 + } + } + + return buf +} + +func writeYCbCrToRGBAImageBuf(img image.Image) []byte { + w := img.Bounds().Dx() + h := img.Bounds().Dy() + i := 0 + buf := make([]byte, w*h*3) + + for y := 0; y < h; y++ { + for x := 0; x < w; x++ { + c := img.At(x, y).(color.YCbCr) + r, g, b, _ := c.RGBA() + buf[i] = uint8(r >> 8 & 0xFF) + buf[i+1] = uint8(g >> 8 & 0xFF) + buf[i+2] = uint8(b >> 8 & 0xFF) + i += 3 + } + } + + return buf +} +func writeNRGBAImageBuf(xRefTable *XRefTable, img image.Image) ([]byte, []byte) { + w := img.Bounds().Dx() + h := img.Bounds().Dy() + i := 0 + buf := make([]byte, w*h*3) + var sm []byte + var softMask bool + + for y := 0; y < h; y++ { + for x := 0; x < w; x++ { + c := img.At(x, y).(color.NRGBA) + if !softMask { + if xRefTable != nil && c.A != 0xFF { + softMask = true + sm = []byte{} + for j := 0; j < y*h+x; j++ { + sm = append(sm, 0xFF) + } + sm = append(sm, c.A) + } + } else { + sm = append(sm, c.A) + } + + buf[i] = c.R + buf[i+1] = c.G + buf[i+2] = c.B + i += 3 + } + } + + return buf, sm +} + +func writeNRGBA64ImageBuf(xRefTable *XRefTable, img image.Image) ([]byte, []byte) { + w := img.Bounds().Dx() + h := img.Bounds().Dy() + i := 0 + buf := make([]byte, w*h*6) + var sm []byte + var softMask bool + + for y := 0; y < h; y++ { + for x := 0; x < w; x++ { + c := img.At(x, y).(color.NRGBA64) + if !softMask { + if xRefTable != nil && c.A != 0xFFFF { + softMask = true + sm = []byte{} + for j := 0; j < y*h+x; j++ { + sm = append(sm, 0xFF) + sm = append(sm, 0xFF) + } + sm = append(sm, uint8(c.A>>8)) + sm = append(sm, uint8(c.A&0x00FF)) + } + } else { + sm = append(sm, uint8(c.A>>8)) + sm = append(sm, uint8(c.A&0x00FF)) + } + + buf[i] = uint8(c.R >> 8) + buf[i+1] = uint8(c.R & 0x00FF) + buf[i+2] = uint8(c.G >> 8) + buf[i+3] = uint8(c.G & 0x00FF) + buf[i+4] = uint8(c.B >> 8) + buf[i+5] = uint8(c.B & 0x00FF) + i += 6 + } + } + + return buf, sm +} + +func writeGrayImageBuf(img image.Image) []byte { + w := img.Bounds().Dx() + h := img.Bounds().Dy() + i := 0 + buf := make([]byte, w*h) + + for y := 0; y < h; y++ { + for x := 0; x < w; x++ { + c := img.At(x, y).(color.Gray) + buf[i] = c.Y + i++ + } + } + + return buf +} + +func writeCMYKImageBuf(img image.Image) []byte { + w := img.Bounds().Dx() + h := img.Bounds().Dy() + i := 0 + buf := make([]byte, w*h*4) + + for y := 0; y < h; y++ { + for x := 0; x < w; x++ { + c := img.At(x, y).(color.CMYK) + buf[i] = c.C + buf[i+1] = c.M + buf[i+2] = c.Y + buf[i+3] = c.K + i += 4 + //fmt.Printf("x:%3d(%3d) y:%3d(%3d) c:#%02x m:#%02x y:#%02x k:#%02x\n", x1, x, y1, y, c.C, c.M, c.Y, c.K) + } + } + + return buf +} + +func convertToRGBA(img image.Image) *image.RGBA { + b := img.Bounds() + m := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy())) + draw.Draw(m, m.Bounds(), img, b.Min, draw.Src) + return m +} + +func imgToImageDict(xRefTable *XRefTable, img image.Image) (*StreamDict, error) { + bpc := 8 + // TODO if dpi != 72 resample (applies to PNG,JPG,TIFF) + w := img.Bounds().Dx() + h := img.Bounds().Dy() + + var buf []byte + var sm []byte // soft mask aka alpha mask + var cs string + + switch img.(type) { + case *image.RGBA: + // A 32-bit alpha-premultiplied color, having 8 bits for each of red, green, blue and alpha. + // An alpha-premultiplied color component C has been scaled by alpha (A), so it has valid values 0 <= C <= A. + cs = DeviceRGBCS + buf = writeRGBAImageBuf(img) + + case *image.RGBA64: + // A 64-bit alpha-premultiplied color, having 16 bits for each of red, green, blue and alpha. + // An alpha-premultiplied color component C has been scaled by alpha (A), so it has valid values 0 <= C <= A. + cs = DeviceRGBCS + bpc = 16 + buf = writeRGBA64ImageBuf(img) + + case *image.NRGBA: + // Non-alpha-premultiplied 32-bit color. + cs = DeviceRGBCS + buf, sm = writeNRGBAImageBuf(xRefTable, img) + + case *image.NRGBA64: + // Non-alpha-premultiplied 64-bit color. + cs = DeviceRGBCS + bpc = 16 + buf, sm = writeNRGBA64ImageBuf(xRefTable, img) + + case *image.Alpha: + return nil, errors.New("unsupported image type: Alpha") + + case *image.Alpha16: + return nil, errors.New("unsupported image type: Alpha16") + + case *image.Gray: + // 8-bit grayscale color. + cs = DeviceGrayCS + buf = writeGrayImageBuf(img) + + case *image.Gray16: + return nil, errors.New("unsupported image type: Gray16") + + case *image.CMYK: + // Opaque CMYK color, having 8 bits for each of cyan, magenta, yellow and black. + cs = DeviceCMYKCS + buf = writeCMYKImageBuf(img) + + case *image.YCbCr: + return nil, errors.New("unsupported image type: YCbCr") + + case *image.NYCbCrA: + return nil, errors.New("unsupported image type: NYCbCrA") + + case *image.Paletted: + // In-memory image of uint8 indices into a given palette. + cs = DeviceRGBCS + buf = writeRGBAImageBuf(convertToRGBA(img)) + + default: + return nil, errors.Errorf("unsupported image type: %T", img) + } + + //fmt.Printf("old w:%3d, h:%3d, new w:%3d, h:%3d\n", img.Bounds().Dx(), img.Bounds().Dy(), w, h) + + return createFlateImageObject(xRefTable, buf, sm, w, h, bpc, cs) +} + +// ReadJPEG generates a PDF image object for a JPEG stream +// and appends this object to the cross reference table. +func ReadJPEG(xRefTable *XRefTable, buf []byte, c image.Config) (*StreamDict, error) { + var cs string + + switch c.ColorModel { + + case color.GrayModel: + cs = DeviceGrayCS + + case color.YCbCrModel: + cs = DeviceRGBCS + + case color.CMYKModel: + cs = DeviceCMYKCS + + default: + return nil, errors.New("pdfcpu: unexpected color model for JPEG") + + } + + return createDCTImageObject(xRefTable, buf, c.Width, c.Height, cs) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/renderImage.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/renderImage.go new file mode 100644 index 0000000..c825814 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/renderImage.go @@ -0,0 +1,803 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bytes" + "image" + "image/color" + "image/png" + "io/ioutil" + "os" + + "github.com/hhrutter/tiff" + "github.com/pdfcpu/pdfcpu/pkg/filter" + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +// Errors to be identified. +var ( + ErrUnsupported16BPC = errors.New("unsupported 16 bits per component") +) + +// colValRange defines a numeric range for color space component values that may be inverted. +type colValRange struct { + min, max float64 + inv bool +} + +// PDFImage represents a XObject of subtype image. +type PDFImage struct { + objNr int + sd *StreamDict + bpc int + w, h int + softMask []byte + decode []colValRange +} + +func decodeArr(a Array) []colValRange { + + if a == nil { + //println("decodearr == nil") + return nil + } + + var decode []colValRange + var min, max, f64 float64 + + for i, f := range a { + switch o := f.(type) { + case Integer: + f64 = float64(o.Value()) + case Float: + f64 = o.Value() + } + if i%2 == 0 { + min = f64 + continue + } + max = f64 + var inv bool + if min > max { + min, max = max, min + inv = true + } + decode = append(decode, colValRange{min: min, max: max, inv: inv}) + } + + return decode +} + +func pdfImage(xRefTable *XRefTable, sd *StreamDict, objNr int) (*PDFImage, error) { + + bpc := *sd.IntEntry("BitsPerComponent") + //if bpc == 16 { + // return nil, ErrUnsupported16BPC + //} + + w := *sd.IntEntry("Width") + h := *sd.IntEntry("Height") + + decode := decodeArr(sd.ArrayEntry("Decode")) + //fmt.Printf("decode: %v\n", decode) + + sm, err := softMask(xRefTable, sd, w, h, objNr) + if err != nil { + return nil, err + } + + return &PDFImage{ + objNr: objNr, + sd: sd, + bpc: bpc, + w: w, + h: h, + softMask: sm, + decode: decode, + }, nil +} + +// Identify the color lookup table for an Indexed color space. +func colorLookupTable(xRefTable *XRefTable, o Object) ([]byte, error) { + + var lookup []byte + var err error + + o, _ = xRefTable.Dereference(o) + + switch o := o.(type) { + + case StringLiteral: + return Unescape(string(o)) + + case HexLiteral: + lookup, err = o.Bytes() + if err != nil { + return nil, err + } + + case StreamDict: + lookup, err = streamBytes(&o) + if err != nil || lookup == nil { + return nil, err + } + } + + return lookup, nil +} + +func decodePixelColorValue(p uint8, bpc, c int, decode []colValRange) uint8 { + + // p ...the color value for this pixel + // c ...applicable index of a color component in the decode array for this pixel. + + if decode == nil { + decode = []colValRange{{min: 0, max: 255}} + } + + min := decode[c].min + max := decode[c].max + + q := 1 + for i := 1; i < bpc; i++ { + q = 2*q + 1 + } + + v := uint8(min + (float64(p) * (max - min) / float64(q))) + + if decode[c].inv { + v = v ^ 0xff + } + + return v +} + +func streamBytes(sd *StreamDict) ([]byte, error) { + + fpl := sd.FilterPipeline + if fpl == nil { + log.Info.Printf("streamBytes: no filter pipeline\n") + if err := sd.Decode(); err != nil { + return nil, err + } + return sd.Content, nil + } + + // Ignore filter chains with length > 1 + if len(fpl) > 1 { + log.Info.Printf("streamBytes: more than 1 filter\n") + return nil, nil + } + + switch fpl[0].Name { + + case filter.Flate: + if err := sd.Decode(); err != nil { + return nil, err + } + + default: + log.Debug.Printf("streamBytes: filter not \"Flate\": %s\n", fpl[0].Name) + return nil, nil + } + + return sd.Content, nil +} + +// Return the soft mask for this image or nil. +func softMask(xRefTable *XRefTable, d *StreamDict, w, h, objNr int) ([]byte, error) { + + // TODO Process optional "Matte". + + o, _ := d.Find("SMask") + if o == nil { + // No soft mask available. + return nil, nil + } + + // Soft mask present. + + sd, _, err := xRefTable.DereferenceStreamDict(o) + if err != nil { + return nil, err + } + + sm, err := streamBytes(sd) + if err != nil { + return nil, err + } + + bpc := sd.IntEntry("BitsPerComponent") + if bpc == nil { + log.Info.Printf("softMask: obj#%d - ignoring soft mask without bpc\n%s\n", objNr, sd) + return nil, nil + } + + // TODO support soft masks with bpc != 8 + // Will need to return the softmask bpc to caller. + if *bpc != 8 { + log.Info.Printf("softMask: obj#%d - ignoring soft mask with bpc=%d\n", objNr, *bpc) + return nil, nil + } + + if sm != nil { + if len(sm) != (*bpc*w*h+7)/8 { + log.Info.Printf("softMask: obj#%d - ignoring corrupt softmask\n%s\n", objNr, sd) + return nil, nil + } + } + + return sm, nil +} + +func renderDeviceCMYKToTIFF(im *PDFImage, resourceName string) (*Image, error) { + + b := im.sd.Content + + log.Debug.Printf("renderDeviceCMYKToTIFF: CMYK objNr=%d w=%d h=%d bpc=%d buflen=%d\n", im.objNr, im.w, im.h, im.bpc, len(b)) + + img := image.NewCMYK(image.Rect(0, 0, im.w, im.h)) + + i := 0 + + // TODO support bpc, decode and softMask. + + for y := 0; y < im.h; y++ { + for x := 0; x < im.w; x++ { + img.Set(x, y, color.CMYK{C: b[i], M: b[i+1], Y: b[i+2], K: b[i+3]}) + i += 4 + } + } + + var buf bytes.Buffer + // TODO softmask handling. + if err := tiff.Encode(&buf, img, nil); err != nil { + return nil, err + } + return &Image{&buf, resourceName, "tif"}, nil +} + +func renderDeviceGrayToPNG(im *PDFImage, resourceName string) (*Image, error) { + + b := im.sd.Content + + log.Debug.Printf("renderDeviceGrayToPNG: objNr=%d w=%d h=%d bpc=%d buflen=%d\n", im.objNr, im.w, im.h, im.bpc, len(b)) + + // Validate buflen. + // For streams not using compression there is a trailing 0x0A in addition to the imagebytes. + if len(b) < (im.bpc*im.w*im.h+7)/8 { + return nil, errors.Errorf("pdfcpu: renderDeviceGrayToPNG: objNr=%d corrupt image object %v\n", im.objNr, *im.sd) + } + + img := image.NewGray(image.Rect(0, 0, im.w, im.h)) + + // TODO support softmask. + i := 0 + for y := 0; y < im.h; y++ { + for x := 0; x < im.w; { + p := b[i] + for j := 0; j < 8/im.bpc; j++ { + pix := p >> (8 - uint8(im.bpc)) + v := decodePixelColorValue(pix, im.bpc, 0, im.decode) + //fmt.Printf("x=%d y=%d pix=#%02x v=#%02x\n", x, y, pix, v) + img.Set(x, y, color.Gray{Y: v}) + p <<= uint8(im.bpc) + x++ + } + i++ + } + } + + var buf bytes.Buffer + if err := png.Encode(&buf, img); err != nil { + return nil, err + } + return &Image{&buf, resourceName, "png"}, nil +} + +func renderDeviceRGBToPNG(im *PDFImage, resourceName string) (*Image, error) { + + b := im.sd.Content + + log.Debug.Printf("renderDeviceRGBToPNG: objNr=%d w=%d h=%d bpc=%d buflen=%d\n", im.objNr, im.w, im.h, im.bpc, len(b)) + + // Validate buflen. + // Sometimes there is a trailing 0x0A in addition to the imagebytes. + if len(b) < (3*im.bpc*im.w*im.h+7)/8 { + return nil, errors.Errorf("pdfcpu: renderDeviceRGBToPNG: objNr=%d corrupt image object\n", im.objNr) + } + + // TODO Support bpc and decode. + img := image.NewNRGBA(image.Rect(0, 0, im.w, im.h)) + + i := 0 + for y := 0; y < im.h; y++ { + for x := 0; x < im.w; x++ { + alpha := uint8(255) + if im.softMask != nil { + alpha = im.softMask[y*im.w+x] + } + img.Set(x, y, color.NRGBA{R: b[i], G: b[i+1], B: b[i+2], A: alpha}) + i += 3 + } + } + + var buf bytes.Buffer + if err := png.Encode(&buf, img); err != nil { + return nil, err + } + return &Image{&buf, resourceName, "png"}, nil +} + +func ensureDeviceRGBCS(xRefTable *XRefTable, o Object) bool { + + o, err := xRefTable.Dereference(o) + if err != nil { + return false + } + + switch altCS := o.(type) { + case Name: + return altCS == DeviceRGBCS + } + + return false +} + +func renderCalRGBToPNG(im *PDFImage, resourceName string) (*Image, error) { + + b := im.sd.Content + + log.Debug.Printf("renderCalRGBToPNG: objNr=%d w=%d h=%d bpc=%d buflen=%d\n", im.objNr, im.w, im.h, im.bpc, len(b)) + + if len(b) < (3*im.bpc*im.w*im.h+7)/8 { + return nil, errors.Errorf("pdfcpu:renderCalRGBToPNG: objNr=%d corrupt image object %v\n", im.objNr, *im.sd) + } + + // Optional int array "Range", length 2*N specifies min,max values of color components. + // This information can be validated against the iccProfile. + + // RGB + // TODO Support bpc, decode and softmask. + img := image.NewNRGBA(image.Rect(0, 0, im.w, im.h)) + i := 0 + for y := 0; y < im.h; y++ { + for x := 0; x < im.w; x++ { + img.Set(x, y, color.NRGBA{R: b[i], G: b[i+1], B: b[i+2], A: 255}) + i += 3 + } + } + + var buf bytes.Buffer + if err := png.Encode(&buf, img); err != nil { + return nil, err + } + return &Image{&buf, resourceName, "png"}, nil +} + +func renderICCBased(xRefTable *XRefTable, im *PDFImage, resourceName string, cs Array) (*Image, error) { + + // Any ICC profile >= ICC.1:2004:10 is sufficient for any PDF version <= 1.7 + // If the embedded ICC profile version is newer than the one used by the Reader, substitute with Alternate color space. + + iccProfileStream, _, _ := xRefTable.DereferenceStreamDict(cs[1]) + + b := im.sd.Content + + log.Debug.Printf("renderICCBasedToPNGFile: objNr=%d w=%d h=%d bpc=%d buflen=%d\n", im.objNr, im.w, im.h, im.bpc, len(b)) + + // 1,3 or 4 color components. + n := *iccProfileStream.IntEntry("N") + + if !IntMemberOf(n, []int{1, 3, 4}) { + return nil, errors.Errorf("pdfcpu: renderICCBasedToPNGFile: objNr=%d, N must be 1,3 or 4, got:%d\n", im.objNr, n) + } + + // TODO: Transform linear XYZ to RGB according to ICC profile. + // For now we fall back to appropriate color spaces for n + // regardless of a specified alternate color space. + + // Validate buflen. + // Sometimes there is a trailing 0x0A in addition to the imagebytes. + if len(b) < (n*im.bpc*im.w*im.h+7)/8 { + return nil, errors.Errorf("pdfcpu: renderICCBased: objNr=%d corrupt image object %v\n", im.objNr, *im.sd) + } + + switch n { + case 1: + // Gray + return renderDeviceGrayToPNG(im, resourceName) + + case 3: + // RGB + return renderDeviceRGBToPNG(im, resourceName) + + case 4: + // CMYK + return renderDeviceCMYKToTIFF(im, resourceName) + } + + return nil, nil +} + +func renderIndexedRGBToPNG(im *PDFImage, resourceName string, lookup []byte) (*Image, error) { + + b := im.sd.Content + + img := image.NewNRGBA(image.Rect(0, 0, im.w, im.h)) + + // TODO handle decode. + + i := 0 + for y := 0; y < im.h; y++ { + for x := 0; x < im.w; { + p := b[i] + for j := 0; j < 8/im.bpc; j++ { + ind := p >> (8 - uint8(im.bpc)) + //fmt.Printf("x=%d y=%d i=%d j=%d p=#%02x ind=#%02x\n", x, y, i, j, p, ind) + alpha := uint8(255) + if im.softMask != nil { + alpha = im.softMask[y*im.w+x] + } + l := 3 * int(ind) + img.Set(x, y, color.NRGBA{R: lookup[l], G: lookup[l+1], B: lookup[l+2], A: alpha}) + p <<= uint8(im.bpc) + x++ + } + i++ + } + } + + var buf bytes.Buffer + if err := png.Encode(&buf, img); err != nil { + return nil, err + } + return &Image{&buf, resourceName, "png"}, nil +} + +func renderIndexedCMYKToTIFF(im *PDFImage, resourceName string, lookup []byte) (*Image, error) { + + b := im.sd.Content + + img := image.NewCMYK(image.Rect(0, 0, im.w, im.h)) + + // TODO handle decode and softmask. + + i := 0 + for y := 0; y < im.h; y++ { + for x := 0; x < im.w; { + p := b[i] + for j := 0; j < 8/im.bpc; j++ { + ind := p >> (8 - uint8(im.bpc)) + //fmt.Printf("x=%d y=%d i=%d j=%d p=#%02x ind=#%02x\n", x, y, i, j, p, ind) + l := 4 * int(ind) + img.Set(x, y, color.CMYK{C: lookup[l], M: lookup[l+1], Y: lookup[l+2], K: lookup[l+3]}) + p <<= uint8(im.bpc) + x++ + } + i++ + } + } + + var buf bytes.Buffer + // TODO softmask handling. + if err := tiff.Encode(&buf, img, nil); err != nil { + return nil, err + } + return &Image{&buf, resourceName, "tif"}, nil +} + +func renderIndexedNameCS(im *PDFImage, resourceName string, cs Name, maxInd int, lookup []byte) (*Image, error) { + + switch cs { + + case DeviceRGBCS: + + if len(lookup) < 3*(maxInd+1) { + return nil, errors.Errorf("pdfcpu: renderIndexedNameCS: objNr=%d, corrupt DeviceRGB lookup table\n", im.objNr) + } + + return renderIndexedRGBToPNG(im, resourceName, lookup) + + case DeviceCMYKCS: + + if len(lookup) < 4*(maxInd+1) { + return nil, errors.Errorf("pdfcpu: renderIndexedNameCS: objNr=%d, corrupt DeviceCMYK lookup table\n", im.objNr) + } + + return renderIndexedCMYKToTIFF(im, resourceName, lookup) + } + + log.Info.Printf("renderIndexedNameCS: objNr=%d, unsupported base colorspace %s\n", im.objNr, cs.String()) + + return nil, nil +} + +func renderIndexedArrayCS(xRefTable *XRefTable, im *PDFImage, resourceName string, csa Array, maxInd int, lookup []byte) (*Image, error) { + + b := im.sd.Content + + cs, _ := csa[0].(Name) + + switch cs { + + case ICCBasedCS: + + iccProfileStream, _, _ := xRefTable.DereferenceStreamDict(csa[1]) + + // 1,3 or 4 color components. + n := *iccProfileStream.IntEntry("N") + if !IntMemberOf(n, []int{1, 3, 4}) { + return nil, errors.Errorf("pdfcpu: renderIndexedArrayCS: objNr=%d, N must be 1,3 or 4, got:%d\n", im.objNr, n) + } + + // Validate the lookup table. + if len(lookup) < n*(maxInd+1) { + return nil, errors.Errorf("pdfcpu: renderIndexedArrayCS: objNr=%d, corrupt ICCBased lookup table\n", im.objNr) + } + + // TODO: Transform linear XYZ to RGB according to ICC profile. + // For now we fall back to approriate color spaces for n + // regardless of a specified alternate color space. + + switch n { + case 1: + // Gray + // TODO use lookupTable! + // TODO handle bpc, decode and softmask. + img := image.NewGray(image.Rect(0, 0, im.w, im.h)) + i := 0 + for y := 0; y < im.h; y++ { + for x := 0; x < im.w; x++ { + img.Set(x, y, color.Gray{Y: b[i]}) + i++ + } + } + var buf bytes.Buffer + if err := png.Encode(&buf, img); err != nil { + return nil, err + } + return &Image{&buf, "", "png"}, nil + + case 3: + // RGB + return renderIndexedRGBToPNG(im, resourceName, lookup) + + case 4: + // CMYK + log.Debug.Printf("renderIndexedArrayCS: CMYK objNr=%d w=%d h=%d bpc=%d buflen=%d\n", im.objNr, im.w, im.h, im.bpc, len(b)) + return renderIndexedCMYKToTIFF(im, resourceName, lookup) + } + } + + log.Info.Printf("renderIndexedArrayCS: objNr=%d, unsupported base colorspace %s\n", im.objNr, csa) + + return nil, nil +} + +func renderIndexed(xRefTable *XRefTable, im *PDFImage, resourceName string, cs Array) (*Image, error) { + + // Identify the base color space. + baseCS, _ := xRefTable.Dereference(cs[1]) + + // Identify the max index into the color lookup table. + maxInd, _ := xRefTable.DereferenceInteger(cs[2]) + + // Identify the color lookup table. + var lookup []byte + lookup, err := colorLookupTable(xRefTable, cs[3]) + if err != nil { + return nil, err + } + if lookup == nil { + return nil, errors.Errorf("pdfcpu: renderIndexed: objNr=%d IndexedCS with corrupt lookup table %s\n", im.objNr, cs) + } + //fmt.Printf("lookup: \n%s\n", hex.Dump(l)) + + b := im.sd.Content + + log.Debug.Printf("renderIndexed: objNr=%d w=%d h=%d bpc=%d buflen=%d maxInd=%d\n", im.objNr, im.w, im.h, im.bpc, len(b), maxInd) + + // Validate buflen. + // The image data is a sequence of index values for pixels. + // Sometimes there is a trailing 0x0A. + if len(b) < (im.bpc*im.w*im.h+7)/8 { + return nil, errors.Errorf("pdfcpu: renderIndexed: objNr=%d corrupt image object %v\n", im.objNr, *im.sd) + } + + switch cs := baseCS.(type) { + case Name: + return renderIndexedNameCS(im, resourceName, cs, maxInd.Value(), lookup) + + case Array: + return renderIndexedArrayCS(xRefTable, im, resourceName, cs, maxInd.Value(), lookup) + } + + return nil, nil +} + +func renderFlateEncodedImage(xRefTable *XRefTable, io *ImageObject, objNr int) (*Image, error) { + + sd := io.ImageDict + resourceName := io.ResourceNames[0] + + pdfImage, err := pdfImage(xRefTable, sd, objNr) + if err != nil { + return nil, err + } + + o, err := xRefTable.DereferenceDictEntry(sd.Dict, "ColorSpace") + if err != nil { + return nil, err + } + + switch cs := o.(type) { + + case Name: + switch cs { + + case DeviceGrayCS: + return renderDeviceGrayToPNG(pdfImage, resourceName) + + case DeviceRGBCS: + return renderDeviceRGBToPNG(pdfImage, resourceName) + + case DeviceCMYKCS: + return renderDeviceCMYKToTIFF(pdfImage, resourceName) + + default: + log.Info.Printf("renderFlateEncodedImage: objNr=%d, unsupported name colorspace %s\n", objNr, cs.String()) + } + + case Array: + csn, _ := cs[0].(Name) + + switch csn { + + case CalRGBCS: + return renderCalRGBToPNG(pdfImage, resourceName) + + case ICCBasedCS: + return renderICCBased(xRefTable, pdfImage, resourceName, cs) + + case IndexedCS: + return renderIndexed(xRefTable, pdfImage, resourceName, cs) + + default: + log.Info.Printf("renderFlateEncodedImage: objNr=%d, unsupported array colorspace %s\n", objNr, csn) + } + + } + + return nil, nil +} + +// RenderImage returns a reader for the encoded image bytes. +func RenderImage(xRefTable *XRefTable, io *ImageObject, objNr int) (*Image, error) { + + sd := io.ImageDict + resourceName := io.ResourceNames[0] + + switch sd.FilterPipeline[0].Name { + + case filter.Flate, filter.CCITTFax: + // If color space is CMYK then write .tif else write .png + return renderFlateEncodedImage(xRefTable, io, objNr) + + case filter.DCT: + return &Image{bytes.NewReader(sd.Raw), resourceName, "jpg"}, nil + + case filter.JPX: + return &Image{bytes.NewReader(sd.Raw), resourceName, "jpx"}, nil + } + + return nil, nil +} + +func renderCSByName(cs Name, pdfImage *PDFImage, filename string, objNr int) (*Image, error) { + switch cs { + + case DeviceGrayCS: + return renderDeviceGrayToPNG(pdfImage, filename) + + case DeviceRGBCS: + return renderDeviceRGBToPNG(pdfImage, filename) + + case DeviceCMYKCS: + return renderDeviceCMYKToTIFF(pdfImage, filename) + + default: + log.Info.Printf("renderCSByName: objNr=%d, unsupported name colorspace %s\n", objNr, cs) + } + + return nil, nil +} + +func renderCSByArray(xRefTable *XRefTable, cs Array, pdfImage *PDFImage, filename string, objNr int) (*Image, error) { + switch cs[0].(Name) { + + case CalRGBCS: + return renderCalRGBToPNG(pdfImage, filename) + + case ICCBasedCS: + return renderICCBased(xRefTable, pdfImage, filename, cs) + + case IndexedCS: + return renderIndexed(xRefTable, pdfImage, filename, cs) + + default: + log.Info.Printf("renderCSByArray: objNr=%d, unsupported array colorspace %s\n", objNr, cs) + } + + return nil, nil +} + +func writeFlateEncodedImage(xRefTable *XRefTable, filename string, sd *StreamDict, objNr int) (string, error) { + + pdfImage, err := pdfImage(xRefTable, sd, objNr) + if err != nil { + return "", err + } + + o, err := xRefTable.DereferenceDictEntry(sd.Dict, "ColorSpace") + if err != nil { + return "", err + } + + var img *Image + + switch cs := o.(type) { + case Name: + img, err = renderCSByName(cs, pdfImage, filename, objNr) + case Array: + img, err = renderCSByArray(xRefTable, cs, pdfImage, filename, objNr) + } + + if err != nil || img == nil { + return "", err + } + + bb, err := ioutil.ReadAll(img) + if err != nil { + return "", err + } + + if err := ioutil.WriteFile(filename, bb, os.ModePerm); err != nil { + return "", err + } + + return filename, nil +} + +// WriteImage writes a PDF image object to disk. +func WriteImage(xRefTable *XRefTable, filename string, sd *StreamDict, objNr int) (string, error) { + switch sd.FilterPipeline[0].Name { + + case filter.Flate, filter.CCITTFax: + return writeFlateEncodedImage(xRefTable, filename, sd, objNr) + + case filter.DCT: + return filename + ".jpx", ioutil.WriteFile(filename, sd.Raw, os.ModePerm) + + case filter.JPX: + return filename + ".jpx", ioutil.WriteFile(filename, sd.Raw, os.ModePerm) + } + + return "", nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/resources.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/resources.go new file mode 100644 index 0000000..b15425b --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/resources.go @@ -0,0 +1,172 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + "strings" +) + +// FontObject represents a font used in a PDF file. +type FontObject struct { + ResourceNames []string + Prefix string + FontName string + FontDict Dict + Data []byte + Extension string +} + +// AddResourceName adds a resourceName referring to this font. +func (fo *FontObject) AddResourceName(resourceName string) { + for _, resName := range fo.ResourceNames { + if resName == resourceName { + return + } + } + fo.ResourceNames = append(fo.ResourceNames, resourceName) +} + +// ResourceNamesString returns a string representation of all the resource names of this font. +func (fo FontObject) ResourceNamesString() string { + var resNames []string + for _, resName := range fo.ResourceNames { + resNames = append(resNames, resName) + } + return strings.Join(resNames, ",") +} + +// Data returns the raw data belonging to this image object. +// func (fo FontObject) Data() []byte { +// return nil +// } + +// SubType returns the SubType of this font. +func (fo FontObject) SubType() string { + var subType string + if fo.FontDict.Subtype() != nil { + subType = *fo.FontDict.Subtype() + } + return subType +} + +// Encoding returns the Encoding of this font. +func (fo FontObject) Encoding() string { + encoding := "Built-in" + pdfObject, found := fo.FontDict.Find("Encoding") + if found { + switch enc := pdfObject.(type) { + case Name: + encoding = enc.Value() + default: + encoding = "Custom" + } + } + return encoding +} + +// Embedded returns true if the font is embedded into this PDF file. +func (fo FontObject) Embedded() (embedded bool) { + + _, embedded = fo.FontDict.Find("FontDescriptor") + + if !embedded { + _, embedded = fo.FontDict.Find("DescendantFonts") + } + + return +} + +func (fo FontObject) String() string { + return fmt.Sprintf("%-10s %-30s %-10s %-20s %-8v %s\n", + fo.Prefix, fo.FontName, + fo.SubType(), fo.Encoding(), + fo.Embedded(), fo.ResourceNamesString()) +} + +// ImageObject represents an image used in a PDF file. +type ImageObject struct { + ResourceNames []string + ImageDict *StreamDict +} + +// AddResourceName adds a resourceName to this imageObject's ResourceNames dict. +func (io *ImageObject) AddResourceName(resourceName string) { + for _, resName := range io.ResourceNames { + if resName == resourceName { + return + } + } + io.ResourceNames = append(io.ResourceNames, resourceName) +} + +// ResourceNamesString returns a string representation of the ResourceNames for this image. +func (io ImageObject) ResourceNamesString() string { + var resNames []string + for _, resName := range io.ResourceNames { + resNames = append(resNames, resName) + } + return strings.Join(resNames, ",") +} + +var resourceTypes = NewStringSet([]string{"ColorSpace", "ExtGState", "Font", "Pattern", "Properties", "Shading", "XObject"}) + +// PageResourceNames represents the required resource names for a specific page as extracted from its content streams. +type PageResourceNames map[string]StringSet + +// NewPageResourceNames returns initialized pageResourceNames. +func NewPageResourceNames() PageResourceNames { + m := make(map[string]StringSet, len(resourceTypes)) + for k := range resourceTypes { + m[k] = StringSet{} + } + return m +} + +// Resources returns a set of all required resource names for subdict s. +func (prn PageResourceNames) Resources(s string) StringSet { + return prn[s] +} + +// HasResources returns true for any resource names present in resource subDict s. +func (prn PageResourceNames) HasResources(s string) bool { + return len(prn.Resources(s)) > 0 +} + +// HasContent returns true in any resource names present. +func (prn PageResourceNames) HasContent() bool { + for k := range resourceTypes { + if prn.HasResources(k) { + return true + } + } + return false +} + +func (prn PageResourceNames) String() string { + sep := ", " + var ss []string + s := []string{"PageResourceNames:\n"} + for k := range resourceTypes { + ss = nil + for k := range prn.Resources(k) { + ss = append(ss, k) + } + s = append(s, k+": "+strings.Join(ss, sep)+"\n") + } + return strings.Join(s, "") +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/rotate.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/rotate.go new file mode 100644 index 0000000..7241df3 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/rotate.go @@ -0,0 +1,49 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import "github.com/pdfcpu/pdfcpu/pkg/log" + +func rotatePage(xRefTable *XRefTable, i, j int) error { + + log.Debug.Printf("rotate page:%d\n", i) + + consolidateRes := false + d, inhPAttrs, err := xRefTable.PageDict(i, consolidateRes) + if err != nil { + return err + } + + d.Update("Rotate", Integer((inhPAttrs.rotate+j)%360)) + + return nil +} + +// RotatePages rotates all selected pages by a multiple of 90 degrees. +func RotatePages(ctx *Context, selectedPages IntSet, rotation int) error { + + for k, v := range selectedPages { + if v { + err := rotatePage(ctx.XRefTable, k, rotation) + if err != nil { + return err + } + } + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/slice.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/slice.go new file mode 100644 index 0000000..7c172a0 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/slice.go @@ -0,0 +1,37 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +// MemberOf returns true if list contains s. +func MemberOf(s string, list []string) bool { + for _, v := range list { + if s == v { + return true + } + } + return false +} + +// IntMemberOf returns true if list contains i. +func IntMemberOf(i int, list []int) bool { + for _, v := range list { + if i == v { + return true + } + } + return false +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/stamp.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/stamp.go new file mode 100644 index 0000000..2b4b490 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/stamp.go @@ -0,0 +1,2389 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bytes" + "encoding/hex" + "fmt" + "image" + "io" + "io/ioutil" + "math" + "os" + "path/filepath" + "strconv" + "strings" + "unicode/utf16" + + "github.com/pdfcpu/pdfcpu/pkg/filter" + "github.com/pdfcpu/pdfcpu/pkg/font" + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pdfcpu/pdfcpu/pkg/types" + + "github.com/pkg/errors" +) + +const stampWithBBox = false + +const ( + degToRad = math.Pi / 180 + radToDeg = 180 / math.Pi +) + +// Watermark mode +const ( + WMText = iota + WMImage + WMPDF +) + +// Rotation along one of 2 diagonals +const ( + NoDiagonal = iota + DiagonalLLToUR + DiagonalULToLR +) + +// RenderMode represents the text rendering mode (see 9.3.6) +type RenderMode int + +// Render mode +const ( + RMFill RenderMode = iota + RMStroke + RMFillAndStroke +) + +var ( + errNoContent = errors.New("pdfcpu: page without content") + errNoWatermark = errors.New("pdfcpu: no watermarks found") + errCorruptOCGs = errors.New("pdfcpu: OCProperties: corrupt OCGs element") +) + +type watermarkParamMap map[string]func(string, *Watermark) error + +// Handle applies parameter completion and if successful +// parses the parameter values into import. +func (m watermarkParamMap) Handle(paramPrefix, paramValueStr string, imp *Watermark) error { + var param string + + // Completion support + for k := range m { + if !strings.HasPrefix(k, paramPrefix) { + continue + } + if len(param) > 0 { + return errors.Errorf("pdfcpu: ambiguous parameter prefix \"%s\"", paramPrefix) + } + param = k + } + + if param == "" { + return errors.Errorf("pdfcpu: unknown parameter prefix \"%s\"", paramPrefix) + } + + return m[param](paramValueStr, imp) +} + +var wmParamMap = watermarkParamMap{ + "aligntext": parseTextHorAlignment, + "backgroundcolor": parseBackgroundColor, + "bgcolor": parseBackgroundColor, + "border": parseBorder, + "color": parseFillColor, + "diagonal": parseDiagonal, + "fillcolor": parseFillColor, + "fontname": parseFontName, + "margins": parseMargins, + "mode": parseRenderMode, + "offset": parsePositionOffsetWM, + "opacity": parseOpacity, + "points": parseFontSize, + "position": parsePositionAnchorWM, + "rendermode": parseRenderMode, + "rotation": parseRotation, + "scalefactor": parseScaleFactorWM, + "strokecolor": parseStrokeColor, +} + +type matrix [3][3]float64 + +var identMatrix = matrix{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}} + +func (m matrix) multiply(n matrix) matrix { + var p matrix + for i := 0; i < 3; i++ { + for j := 0; j < 3; j++ { + for k := 0; k < 3; k++ { + p[i][j] += m[i][k] * n[k][j] + } + } + } + return p +} + +func (m matrix) String() string { + return fmt.Sprintf("%3.2f %3.2f %3.2f\n%3.2f %3.2f %3.2f\n%3.2f %3.2f %3.2f\n", + m[0][0], m[0][1], m[0][2], + m[1][0], m[1][1], m[1][2], + m[2][0], m[2][1], m[2][2]) +} + +// SimpleColor is a simple rgb wrapper. +type SimpleColor struct { + R, G, B float32 // intensities between 0 and 1. +} + +func (sc SimpleColor) String() string { + return fmt.Sprintf("r=%1.1f g=%1.1f b=%1.1f", sc.R, sc.G, sc.B) +} + +// NewSimpleColor returns a SimpleColor for rgb in the form 0x00RRGGBB +func NewSimpleColor(rgb uint32) SimpleColor { + r := float32((rgb>>16)&0xFF) / 255 + g := float32((rgb>>8)&0xFF) / 255 + b := float32(rgb&0xFF) / 255 + return SimpleColor{r, g, b} +} + +// Some popular colors. +var ( + Black = SimpleColor{} + White = SimpleColor{R: 1, G: 1, B: 1} + Gray = SimpleColor{.5, .5, .5} + LightGray = SimpleColor{.9, .9, .9} +) + +type formCache map[types.Rectangle]*IndirectRef + +type pdfResources struct { + content []byte + resDict *IndirectRef + bb *Rectangle +} + +// Watermark represents the basic structure and command details for the commands "Stamp" and "Watermark". +type Watermark struct { + // configuration + Mode int // WMText, WMImage or WMPDF + TextString string // raw display text. + TextLines []string // display multiple lines of text. + FileName string // display pdf page or png image. + Page int // the page number of a PDF file. 0 means multistamp/multiwatermark. + OnTop bool // if true this is a STAMP else this is a WATERMARK. + InpUnit DisplayUnit // input display unit. + Pos anchor // position anchor, one of tl,tc,tr,l,c,r,bl,bc,br. + Dx, Dy int // anchor offset. + HAlign *HAlignment // horizonal alignment for text watermarks. + FontName string // supported are Adobe base fonts only. (as of now: Helvetica, Times-Roman, Courier) + FontSize int // font scaling factor. + ScaledFontSize int // font scaling factor for a specific page + Color SimpleColor // text fill color(=non stroking color) for backwards compatibility. + FillColor SimpleColor // text fill color(=non stroking color). + StrokeColor SimpleColor // text stroking color + BgColor *SimpleColor // text bounding box background color + MLeft, MRight int // left and right bounding box margin + MTop, MBot int // top and bottom bounding box margin + BorderWidth int // Border width, visible if BgColor is set. + BorderStyle LineJoinStyle // Border style (bounding box corner style), visible if BgColor is set. + BorderColor *SimpleColor // border color + Rotation float64 // rotation to apply in degrees. -180 <= x <= 180 + Diagonal int // paint along the diagonal. + UserRotOrDiagonal bool // true if one of rotation or diagonal provided overriding the default. + Opacity float64 // opacity the watermark. 0 <= x <= 1 + RenderMode RenderMode // fill=0, stroke=1 fill&stroke=2 + Scale float64 // relative scale factor: 0 <= x <= 1, absolute scale factor: 0 <= x + ScaleEff float64 // effective scale factor + ScaleAbs bool // true for absolute scaling. + Update bool // true for updating instead of adding a page watermark. + + // resources + ocg, extGState, font, image *IndirectRef + + // image or PDF watermark + width, height int // image or page dimensions. + bbPDF *Rectangle + + // PDF watermark + pdfRes map[int]pdfResources + + // page specific + bb *Rectangle // bounding box of the form representing this watermark. + vp *Rectangle // page dimensions. + pageRot float64 // page rotation in effect. + form *IndirectRef // Forms are dependent on given page dimensions. + + // house keeping + objs IntSet // objects for which wm has been applied already. + fCache formCache // form cache. +} + +// DefaultWatermarkConfig returns the default configuration. +func DefaultWatermarkConfig() *Watermark { + return &Watermark{ + Page: 0, + FontName: "Helvetica", + FontSize: 24, + Pos: Center, + Scale: 0.5, + ScaleAbs: false, + Color: Gray, + StrokeColor: Gray, + FillColor: Gray, + Diagonal: DiagonalLLToUR, + Opacity: 1.0, + RenderMode: RMFill, + pdfRes: map[int]pdfResources{}, + objs: IntSet{}, + fCache: formCache{}, + TextLines: []string{}, + } +} + +func (wm Watermark) typ() string { + if wm.isImage() { + return "image" + } + if wm.isPDF() { + return "pdf" + } + return "text" +} + +func (wm Watermark) String() string { + var s string + if !wm.OnTop { + s = "not " + } + + t := wm.TextString + if len(t) == 0 { + t = wm.FileName + } + + sc := "relative" + if wm.ScaleAbs { + sc = "absolute" + } + + bbox := "" + if wm.bb != nil { + bbox = (*wm.bb).String() + } + + vp := "" + if wm.vp != nil { + vp = (*wm.vp).String() + } + + return fmt.Sprintf("Watermark: <%s> is %son top, typ:%s\n"+ + "%s %d points\n"+ + "PDFpage#: %d\n"+ + "scaling: %.1f %s\n"+ + "color: %s\n"+ + "rotation: %.1f\n"+ + "diagonal: %d\n"+ + "opacity: %.1f\n"+ + "renderMode: %d\n"+ + "bbox:%s\n"+ + "vp:%s\n"+ + "pageRotation: %.1f\n", + t, s, wm.typ(), + wm.FontName, wm.FontSize, + wm.Page, + wm.Scale, sc, + wm.Color, + wm.Rotation, + wm.Diagonal, + wm.Opacity, + wm.RenderMode, + bbox, + vp, + wm.pageRot, + ) +} + +// OnTopString returns "watermark" or "stamp" whichever applies. +func (wm Watermark) OnTopString() string { + s := "watermark" + if wm.OnTop { + s = "stamp" + } + return s +} + +func (wm Watermark) multiStamp() bool { + return wm.Page == 0 +} + +func (wm Watermark) calcMaxTextWidth() float64 { + var maxWidth float64 + for _, l := range wm.TextLines { + w := font.TextWidth(l, wm.FontName, wm.ScaledFontSize) + if w > maxWidth { + maxWidth = w + } + } + return maxWidth +} + +func (wm Watermark) textDescriptor() TextDescriptor { + td := TextDescriptor{ + Text: wm.TextString, + FontName: wm.FontName, + FontSize: wm.FontSize, + Scale: wm.Scale, + ScaleAbs: wm.ScaleAbs, + RMode: wm.RenderMode, + StrokeCol: wm.StrokeColor, + FillCol: wm.FillColor, + ShowBackground: true, + } + if wm.BgColor != nil { + td.ShowTextBB = true + td.BackgroundCol = *wm.BgColor + } + return td +} + +func parseTextHorAlignment(s string, wm *Watermark) error { + var a HAlignment + switch s { + case "l": + a = AlignLeft + case "r": + a = AlignRight + case "c": + a = AlignCenter + case "j": + a = AlignJustify + default: + return errors.Errorf("pdfcpu: unknown horizontal alignment (l,r,c,j): %s", s) + } + + wm.HAlign = &a + + return nil +} + +func parsePositionAnchorWM(s string, wm *Watermark) error { + a, err := parsePositionAnchor(s) + if err != nil { + return err + } + wm.Pos = a + return nil +} + +func parsePositionOffsetWM(s string, wm *Watermark) error { + d := strings.Split(s, " ") + if len(d) != 2 { + return errors.Errorf("pdfcpu: illegal position offset string: need 2 numeric values, %s\n", s) + } + + f, err := strconv.ParseFloat(d[0], 64) + if err != nil { + return err + } + wm.Dx = int(toUserSpace(f, wm.InpUnit)) + + f, err = strconv.ParseFloat(d[1], 64) + if err != nil { + return err + } + wm.Dy = int(toUserSpace(f, wm.InpUnit)) + + return nil +} + +func parseScaleFactorWM(s string, wm *Watermark) (err error) { + wm.Scale, wm.ScaleAbs, err = parseScaleFactor(s) + return err +} + +func parseFontName(s string, wm *Watermark) error { + if !font.SupportedFont(s) { + return errors.Errorf("pdfcpu: %s is unsupported, please refer to \"pdfcpu fonts list\".\n", s) + } + wm.FontName = s + return nil +} + +func parseFontSize(s string, wm *Watermark) error { + fs, err := strconv.Atoi(s) + if err != nil { + return err + } + + wm.FontSize = fs + + return nil +} + +func parseScaleFactor(s string) (float64, bool, error) { + ss := strings.Split(s, " ") + if len(ss) > 2 { + return 0, false, errors.Errorf("pdfcpu: invalid scale string %s: 0.0 < i <= 1.0 {rel} | 0.0 < i {abs}\n", s) + } + + sc, err := strconv.ParseFloat(ss[0], 64) + if err != nil { + return 0, false, errors.Errorf("pdfcpu: scale factor must be a float value: %s\n", ss[0]) + } + + if sc <= 0 { + return 0, false, errors.Errorf("pdfcpu: invalid scale value %.2f: 0.0 < i <= 1.0 {rel} | 0.0 < i {abs}\n", sc) + } + + var scaleAbs bool + + if len(ss) == 1 { + // Assume relative scaling for sc <= 1 and absolute scaling for sc > 1. + scaleAbs = sc > 1 + return sc, scaleAbs, nil + } + + switch ss[1] { + case "a", "abs": + scaleAbs = true + + case "r", "rel": + scaleAbs = false + + default: + return 0, false, errors.Errorf("pdfcpu: illegal scale mode: abs|rel, %s\n", ss[1]) + } + + if !scaleAbs && sc > 1 { + return 0, false, errors.Errorf("pdfcpu: invalid relative scale value %.2f: 0.0 < i <= 1\n", sc) + } + + return sc, scaleAbs, nil +} + +func parseHexColor(hexCol string) (SimpleColor, error) { + var sc SimpleColor + if len(hexCol) != 7 || hexCol[0] != '#' { + return sc, errors.Errorf("pdfcpu: invalid hex color string: #FFFFFF, %s\n", hexCol) + } + b, err := hex.DecodeString(hexCol[1:]) + if err != nil || len(b) != 3 { + return sc, errors.Errorf("pdfcpu: invalid hex color string: #FFFFFF, %s\n", hexCol) + } + return SimpleColor{float32(b[0]) / 255, float32(b[1]) / 255, float32(b[2]) / 255}, nil +} + +func parseColor(s string) (SimpleColor, error) { + var sc SimpleColor + + cs := strings.Split(s, " ") + if len(cs) != 1 && len(cs) != 3 { + return sc, errors.Errorf("pdfcpu: illegal color string: 3 intensities 0.0 <= i <= 1.0 or #FFFFFF, %s\n", s) + } + + if len(cs) == 1 { + // #FFFFFF to uint32 + return parseHexColor(cs[0]) + } + + r, err := strconv.ParseFloat(cs[0], 32) + if err != nil { + return sc, errors.Errorf("red must be a float value: %s\n", cs[0]) + } + if r < 0 || r > 1 { + return sc, errors.New("pdfcpu: red: a color value is an intensity between 0.0 and 1.0") + } + sc.R = float32(r) + + g, err := strconv.ParseFloat(cs[1], 32) + if err != nil { + return sc, errors.Errorf("pdfcpu: green must be a float value: %s\n", cs[1]) + } + if g < 0 || g > 1 { + return sc, errors.New("pdfcpu: green: a color value is an intensity between 0.0 and 1.0") + } + sc.G = float32(g) + + b, err := strconv.ParseFloat(cs[2], 32) + if err != nil { + return sc, errors.Errorf("pdfcpu: blue must be a float value: %s\n", cs[2]) + } + if b < 0 || b > 1 { + return sc, errors.New("pdfcpu: blue: a color value is an intensity between 0.0 and 1.0") + } + sc.B = float32(b) + + return sc, nil +} + +func parseStrokeColor(s string, wm *Watermark) error { + c, err := parseColor(s) + if err != nil { + return err + } + wm.StrokeColor = c + return nil +} + +func parseFillColor(s string, wm *Watermark) error { + c, err := parseColor(s) + if err != nil { + return err + } + wm.FillColor = c + return nil +} + +func parseBackgroundColor(s string, wm *Watermark) error { + c, err := parseColor(s) + if err != nil { + return err + } + wm.BgColor = &c + return nil +} + +func parseRotation(s string, wm *Watermark) error { + if wm.UserRotOrDiagonal { + return errors.New("pdfcpu: please specify rotation or diagonal (r or d)") + } + + r, err := strconv.ParseFloat(s, 64) + if err != nil { + return errors.Errorf("pdfcpu: rotation must be a float value: %s\n", s) + } + if r < -180 || r > 180 { + return errors.Errorf("pdfcpu: illegal rotation: -180 <= r <= 180 degrees, %s\n", s) + } + + wm.Rotation = r + wm.Diagonal = NoDiagonal + wm.UserRotOrDiagonal = true + + return nil +} + +func parseDiagonal(s string, wm *Watermark) error { + if wm.UserRotOrDiagonal { + return errors.New("pdfcpu: please specify rotation or diagonal (r or d)") + } + + d, err := strconv.Atoi(s) + if err != nil { + return errors.Errorf("pdfcpu: illegal diagonal value: allowed 1 or 2, %s\n", s) + } + if d != DiagonalLLToUR && d != DiagonalULToLR { + return errors.New("pdfcpu: diagonal: 1..lower left to upper right, 2..upper left to lower right") + } + + wm.Diagonal = d + wm.Rotation = 0 + wm.UserRotOrDiagonal = true + + return nil +} + +func parseOpacity(s string, wm *Watermark) error { + o, err := strconv.ParseFloat(s, 64) + if err != nil { + return errors.Errorf("pdfcpu: opacity must be a float value: %s\n", s) + } + if o < 0 || o > 1 { + return errors.Errorf("pdfcpu: illegal opacity: 0.0 <= r <= 1.0, %s\n", s) + } + wm.Opacity = o + + return nil +} + +func parseRenderMode(s string, wm *Watermark) error { + m, err := strconv.Atoi(s) + if err != nil { + return errors.Errorf("pdfcpu: illegal render mode value: allowed 0,1,2, %s\n", s) + } + rm := RenderMode(m) + if rm != RMFill && rm != RMStroke && rm != RMFillAndStroke { + return errors.New("pdfcpu: valid rendermodes: 0..fill, 1..stroke, 2..fill&stroke") + } + wm.RenderMode = rm + + return nil +} + +func parseMargins(s string, wm *Watermark) error { + var err error + + m := strings.Split(s, " ") + if len(m) == 0 || len(m) > 4 { + return errors.Errorf("pdfcpu: margins: need 1,2,3 or 4 int values, %s\n", s) + } + + f, err := strconv.ParseFloat(m[0], 64) + if err != nil { + return err + } + i := int(toUserSpace(f, wm.InpUnit)) + + if len(m) == 1 { + wm.MLeft = i + wm.MRight = i + wm.MTop = i + wm.MBot = i + return nil + } + + f, err = strconv.ParseFloat(m[1], 64) + if err != nil { + return err + } + j := int(toUserSpace(f, wm.InpUnit)) + + if len(m) == 2 { + wm.MTop, wm.MBot = i, i + wm.MLeft, wm.MRight = j, j + return nil + } + + f, err = strconv.ParseFloat(m[2], 64) + if err != nil { + return err + } + k := int(toUserSpace(f, wm.InpUnit)) + + if len(m) == 3 { + wm.MTop = i + wm.MLeft, wm.MRight = j, j + wm.MBot = k + return nil + } + + f, err = strconv.ParseFloat(m[3], 64) + if err != nil { + return err + } + l := int(toUserSpace(f, wm.InpUnit)) + + wm.MTop = i + wm.MRight = j + wm.MBot = k + wm.MLeft = l + return nil +} + +func parseBorder(s string, wm *Watermark) error { + // w + // w r g b + // w #c + // w round + // w round r g b + // w round #c + + var err error + + b := strings.Split(s, " ") + if len(b) == 0 || len(b) > 5 { + return errors.Errorf("pdfcpu: borders: need 1,2,3,4 or 5 int values, %s\n", s) + } + + wm.BorderWidth, err = strconv.Atoi(b[0]) + if err != nil { + return err + } + if wm.BorderWidth == 0 { + return errors.New("pdfcpu: borders: need width > 0") + } + + if len(b) == 1 { + return nil + } + + if strings.HasPrefix("round", b[1]) { + wm.BorderStyle = LJRound + if len(b) == 2 { + return nil + } + c, err := parseColor(strings.Join(b[2:], " ")) + wm.BorderColor = &c + return err + } + + c, err := parseColor(strings.Join(b[1:], " ")) + wm.BorderColor = &c + return err +} + +func parseWatermarkDetails(mode int, modeParm, s string, onTop bool, u DisplayUnit) (*Watermark, error) { + wm := DefaultWatermarkConfig() + wm.OnTop = onTop + wm.InpUnit = u + + ss := strings.Split(s, ",") + if len(ss) > 0 && len(ss[0]) == 0 { + setWatermarkType(mode, modeParm, wm) + return wm, nil + } + + for _, s := range ss { + + ss1 := strings.Split(s, ":") + if len(ss1) != 2 { + return nil, parseWatermarkError(onTop) + } + + paramPrefix := strings.TrimSpace(ss1[0]) + paramValueStr := strings.TrimSpace(ss1[1]) + + if err := wmParamMap.Handle(paramPrefix, paramValueStr, wm); err != nil { + return nil, err + } + } + + return wm, setWatermarkType(mode, modeParm, wm) +} + +// ParseTextWatermarkDetails parses a text Watermark/Stamp command string into an internal structure. +func ParseTextWatermarkDetails(text, desc string, onTop bool, u DisplayUnit) (*Watermark, error) { + return parseWatermarkDetails(WMText, text, desc, onTop, u) +} + +// ParseImageWatermarkDetails parses a text Watermark/Stamp command string into an internal structure. +func ParseImageWatermarkDetails(fileName, desc string, onTop bool, u DisplayUnit) (*Watermark, error) { + return parseWatermarkDetails(WMImage, fileName, desc, onTop, u) +} + +// ParsePDFWatermarkDetails parses a text Watermark/Stamp command string into an internal structure. +func ParsePDFWatermarkDetails(fileName, desc string, onTop bool, u DisplayUnit) (*Watermark, error) { + return parseWatermarkDetails(WMPDF, fileName, desc, onTop, u) +} + +func (wm Watermark) calcMinFontSize(w float64) int { + var minSize int + for _, l := range wm.TextLines { + w := font.Size(l, wm.FontName, w) + if minSize == 0.0 { + minSize = w + } + if w < minSize { + minSize = w + } + } + return minSize +} + +// IsText returns true if the watermark content is text. +func (wm Watermark) isText() bool { + return wm.Mode == WMText +} + +// IsPDF returns true if the watermark content is PDF. +func (wm Watermark) isPDF() bool { + return wm.Mode == WMPDF +} + +// IsImage returns true if the watermark content is an image. +func (wm Watermark) isImage() bool { + return wm.Mode == WMImage +} + +func (wm *Watermark) calcBoundingBox(pageNr int) { + bb := RectForDim(float64(wm.width), float64(wm.height)) + + if wm.isPDF() { + wm.bbPDF = wm.pdfRes[wm.Page].bb + if wm.multiStamp() { + i := pageNr + if i > len(wm.pdfRes) { + i = len(wm.pdfRes) + } + wm.bbPDF = wm.pdfRes[i].bb + } + wm.width = int(wm.bbPDF.Width()) + wm.height = int(wm.bbPDF.Height()) + bb = wm.bbPDF + } + + ar := bb.AspectRatio() + + if wm.ScaleAbs { + w1 := wm.Scale * bb.Width() + bb.UR.X = bb.LL.X + w1 + bb.UR.Y = bb.LL.Y + w1/ar + wm.bb = bb + wm.ScaleEff = wm.Scale + return + } + + if ar >= 1 { + // Landscape + w1 := wm.Scale * wm.vp.Width() + bb.UR.X = bb.LL.X + w1 + bb.UR.Y = bb.LL.Y + w1/ar + wm.ScaleEff = w1 / float64(wm.width) + } else { + // Portrait + h1 := wm.Scale * wm.vp.Height() + bb.UR.Y = bb.LL.Y + h1 + bb.UR.X = bb.LL.X + h1*ar + wm.ScaleEff = h1 / float64(wm.height) + } + + wm.bb = bb + return +} + +func (wm *Watermark) calcTransformMatrix() *matrix { + var sin, cos float64 + r := wm.Rotation + + if wm.Diagonal != NoDiagonal { + + // Calculate the angle of the diagonal with respect of the aspect ratio of the bounding box. + r = math.Atan(wm.vp.Height()/wm.vp.Width()) * float64(radToDeg) + + if wm.bb.AspectRatio() < 1 { + r -= 90 + } + + if wm.Diagonal == DiagonalULToLR { + r = -r + } + + } + + sin = math.Sin(float64(r) * float64(degToRad)) + cos = math.Cos(float64(r) * float64(degToRad)) + + // 1) Rotate + m1 := identMatrix + m1[0][0] = cos + m1[0][1] = sin + m1[1][0] = -sin + m1[1][1] = cos + + // 2) Translate + m2 := identMatrix + var dy float64 + if !wm.isImage() && !wm.isPDF() { + dy = wm.bb.LL.Y + } + ll := lowerLeftCorner(wm.vp.Width(), wm.vp.Height(), wm.bb.Width(), wm.bb.Height(), wm.Pos) + m2[2][0] = ll.X + wm.bb.Width()/2 + float64(wm.Dx) + sin*(wm.bb.Height()/2+dy) - cos*wm.bb.Width()/2 + m2[2][1] = ll.Y + wm.bb.Height()/2 + float64(wm.Dy) - cos*(wm.bb.Height()/2+dy) - sin*wm.bb.Width()/2 + + m := m1.multiply(m2) + return &m +} + +func onTopString(onTop bool) string { + e := "watermark" + if onTop { + e = "stamp" + } + return e +} + +func parseWatermarkError(onTop bool) error { + s := onTopString(onTop) + return errors.Errorf("Invalid %s configuration string. Please consult pdfcpu help %s.\n", s, s) +} + +func setWatermarkType(mode int, s string, wm *Watermark) error { + wm.Mode = mode + + switch mode { + case WMText: + wm.TextString = s + if font.IsCoreFont(wm.FontName) { + bb := []byte{} + for _, r := range s { + // Unicode => char code + b := byte(0x20) // better use glyph: .notdef + if r <= 0xff { + b = byte(r) + } + bb = append(bb, b) + } + s = string(bb) + } else { + bb := []byte{} + u := utf16.Encode([]rune(s)) + for _, i := range u { + bb = append(bb, byte((i>>8)&0xFF)) + bb = append(bb, byte(i&0xFF)) + } + s = string(bb) + } + s = strings.ReplaceAll(s, "\\n", "\n") + for _, l := range strings.FieldsFunc(s, func(c rune) bool { return c == 0x0a }) { + wm.TextLines = append(wm.TextLines, l) + } + + case WMImage: + ext := strings.ToLower(filepath.Ext(s)) + if !MemberOf(ext, []string{".jpg", ".jpeg", ".png", ".tif", ".tiff"}) { + return errors.New("imageFileName has to have one of these extensions: jpg, jpeg, png, tif, tiff") + } + wm.FileName = s + + case WMPDF: + i := strings.LastIndex(s, ":") + if i < 1 { + // No Colon. + if strings.ToLower(filepath.Ext(s)) != ".pdf" { + return errors.Errorf("%s is not a PDF file", s) + } + wm.FileName = s + return nil + } + // We have at least one Colon. + if strings.ToLower(filepath.Ext(s)) == ".pdf" { + // We have an absolute DOS filename. + wm.FileName = s + return nil + } + // We expect a page number on the right side of the right most Colon. + var err error + pageNumberStr := s[i+1:] + wm.Page, err = strconv.Atoi(pageNumberStr) + if err != nil { + return errors.Errorf("illegal PDF page number: %s\n", pageNumberStr) + } + fileName := s[:i] + if strings.ToLower(filepath.Ext(fileName)) != ".pdf" { + return errors.Errorf("%s is not a PDF file", fileName) + } + wm.FileName = fileName + } + + return nil +} + +func migrateIndRef(ir *IndirectRef, ctxSource, ctxDest *Context, migrated map[int]int) (Object, error) { + o, err := ctxSource.Dereference(*ir) + if err != nil { + return nil, err + } + + if o != nil { + o = o.Clone() + } + + objNrNew, err := ctxDest.InsertObject(o) + if err != nil { + return nil, err + } + + objNr := ir.ObjectNumber.Value() + migrated[objNr] = objNrNew + ir.ObjectNumber = Integer(objNrNew) + return o, nil +} + +func migrateObject(o Object, ctxSource, ctxDest *Context, migrated map[int]int) (Object, error) { + var err error + switch o := o.(type) { + case IndirectRef: + objNr := o.ObjectNumber.Value() + if migrated[objNr] > 0 { + o.ObjectNumber = Integer(migrated[objNr]) + return o, nil + } + o1, err := migrateIndRef(&o, ctxSource, ctxDest, migrated) + if err != nil { + return nil, err + } + if _, err := migrateObject(o1, ctxSource, ctxDest, migrated); err != nil { + return nil, err + } + return o, nil + + case Dict: + for k, v := range o { + if o[k], err = migrateObject(v, ctxSource, ctxDest, migrated); err != nil { + return nil, err + } + } + return o, nil + + case StreamDict: + for k, v := range o.Dict { + if o.Dict[k], err = migrateObject(v, ctxSource, ctxDest, migrated); err != nil { + return nil, err + } + } + return o, nil + + case Array: + for k, v := range o { + if o[k], err = migrateObject(v, ctxSource, ctxDest, migrated); err != nil { + return nil, err + } + } + return o, nil + } + + return o, nil +} + +func createPDFRes(ctx, otherCtx *Context, pageNr int, migrated map[int]int, wm *Watermark) error { + pdfRes := pdfResources{} + xRefTable := ctx.XRefTable + otherXRefTable := otherCtx.XRefTable + + // Locate page dict & resource dict of PDF stamp. + consolidateRes := true + d, inhPAttrs, err := otherXRefTable.PageDict(pageNr, consolidateRes) + if err != nil { + return err + } + if d == nil { + return errors.Errorf("pdfcpu: unknown page number: %d\n", pageNr) + } + + // Retrieve content stream bytes of page dict. + pdfRes.content, err = otherXRefTable.PageContent(d) + if err != nil { + return err + } + + // Migrate external resource dict into ctx. + if _, err = migrateObject(inhPAttrs.resources, otherCtx, ctx, migrated); err != nil { + return err + } + + // Create an object for resource dict in xRefTable. + ir, err := xRefTable.IndRefForNewObject(inhPAttrs.resources) + if err != nil { + return err + } + + pdfRes.resDict = ir + pdfRes.bb = viewPort(inhPAttrs) + wm.pdfRes[pageNr] = pdfRes + + return nil +} + +func (ctx *Context) createPDFResForWM(wm *Watermark) error { + // Note: The stamp pdf is assumed to be valid! + otherCtx, err := ReadFile(wm.FileName, NewDefaultConfiguration()) + if err != nil { + return err + } + + if err := otherCtx.EnsurePageCount(); err != nil { + return nil + } + + migrated := map[int]int{} + + if !wm.multiStamp() { + if err := createPDFRes(ctx, otherCtx, wm.Page, migrated, wm); err != nil { + return err + } + } else { + j := otherCtx.PageCount + if ctx.PageCount < otherCtx.PageCount { + j = ctx.PageCount + } + for i := 1; i <= j; i++ { + if err := createPDFRes(ctx, otherCtx, i, migrated, wm); err != nil { + return err + } + } + } + + return nil +} + +func createImageResource(xRefTable *XRefTable, r io.Reader) (*IndirectRef, int, int, error) { + bb, err := ioutil.ReadAll(r) + if err != nil { + return nil, 0, 0, err + } + + var sd *StreamDict + r = bytes.NewReader(bb) + + // We identify JPG via its magic bytes. + if bytes.HasPrefix(bb, []byte("\xff\xd8")) { + // Process JPG by wrapping byte stream into DCTEncoded object stream. + c, _, err := image.DecodeConfig(r) + if err != nil { + return nil, 0, 0, err + } + + sd, err = ReadJPEG(xRefTable, bb, c) + if err != nil { + return nil, 0, 0, err + } + + } else { + // Process other formats by decoding into an image + // and subsequent object stream encoding, + img, _, err := image.Decode(r) + if err != nil { + return nil, 0, 0, err + } + + sd, err = imgToImageDict(xRefTable, img) + if err != nil { + return nil, 0, 0, err + } + } + + w := *sd.IntEntry("Width") + h := *sd.IntEntry("Height") + + indRef, err := xRefTable.IndRefForNewObject(*sd) + if err != nil { + return nil, 0, 0, err + } + + return indRef, w, h, nil +} + +func (ctx *Context) createImageResForWM(wm *Watermark) (err error) { + f, err := os.Open(wm.FileName) + if err != nil { + return err + } + defer f.Close() + + wm.image, wm.width, wm.height, err = createImageResource(ctx.XRefTable, f) + return err +} + +func (ctx *Context) createFontResForWM(wm *Watermark) (err error) { + // TODO Take existing font dicts into account. + if font.IsUserFont(wm.FontName) { + // Dummy call in order to setup used glyphs. + WriteMultiLine(new(bytes.Buffer), RectForFormat("A4"), nil, setupTextDescriptor(wm)) + } + wm.font, err = createFontDict(ctx.XRefTable, wm.FontName) + return err +} + +func (ctx *Context) createResourcesForWM(wm *Watermark) error { + if wm.isPDF() { + return ctx.createPDFResForWM(wm) + } + if wm.isImage() { + return ctx.createImageResForWM(wm) + } + return ctx.createFontResForWM(wm) +} + +func (ctx *Context) ensureOCG(onTop bool) (*IndirectRef, error) { + name := "Background" + subt := "BG" + if onTop { + name = "Watermark" + subt = "FG" + } + + d := Dict( + map[string]Object{ + "Name": StringLiteral(name), + "Type": Name("OCG"), + "Usage": Dict( + map[string]Object{ + "PageElement": Dict(map[string]Object{"Subtype": Name(subt)}), + "View": Dict(map[string]Object{"ViewState": Name("ON")}), + "Print": Dict(map[string]Object{"PrintState": Name("ON")}), + "Export": Dict(map[string]Object{"ExportState": Name("ON")}), + }, + ), + }, + ) + + return ctx.IndRefForNewObject(d) +} + +func (ctx *Context) prepareOCPropertiesInRoot(onTop bool) (*IndirectRef, error) { + rootDict, err := ctx.Catalog() + if err != nil { + return nil, err + } + + if o, ok := rootDict.Find("OCProperties"); ok { + + d, err := ctx.DereferenceDict(o) + if err != nil { + return nil, err + } + + o, found := d.Find("OCGs") + if found { + a, err := ctx.DereferenceArray(o) + if err != nil { + return nil, errCorruptOCGs + } + + ir, ok := a[0].(IndirectRef) + if !ok { + return nil, errCorruptOCGs + } + return &ir, nil + } + } + + ir, err := ctx.ensureOCG(onTop) + if err != nil { + return nil, err + } + + optionalContentConfigDict := Dict( + map[string]Object{ + "AS": Array{ + Dict( + map[string]Object{ + "Category": NewNameArray("View"), + "Event": Name("View"), + "OCGs": Array{*ir}, + }, + ), + Dict( + map[string]Object{ + "Category": NewNameArray("Print"), + "Event": Name("Print"), + "OCGs": Array{*ir}, + }, + ), + Dict( + map[string]Object{ + "Category": NewNameArray("Export"), + "Event": Name("Export"), + "OCGs": Array{*ir}, + }, + ), + }, + "ON": Array{*ir}, + "Order": Array{}, + "RBGroups": Array{}, + }, + ) + + d := Dict( + map[string]Object{ + "OCGs": Array{*ir}, + "D": optionalContentConfigDict, + }, + ) + + rootDict.Update("OCProperties", d) + return ir, nil +} + +func (ctx *Context) createFormResDict(pageNr int, wm *Watermark) (*IndirectRef, error) { + if wm.isPDF() { + i := wm.Page + if wm.multiStamp() { + maxStampPageNr := len(wm.pdfRes) + i = pageNr + if pageNr > maxStampPageNr { + i = maxStampPageNr + } + } + return wm.pdfRes[i].resDict, nil + } + + if wm.isImage() { + d := Dict( + map[string]Object{ + "ProcSet": NewNameArray("PDF", "Text", "ImageB", "ImageC", "ImageI"), + "XObject": Dict(map[string]Object{"Im0": *wm.image}), + }, + ) + return ctx.IndRefForNewObject(d) + } + + d := Dict( + map[string]Object{ + "Font": Dict(map[string]Object{"F1": *wm.font}), + "ProcSet": NewNameArray("PDF", "Text", "ImageB", "ImageC", "ImageI"), + }, + ) + + return ctx.IndRefForNewObject(d) +} + +func cachedForm(wm *Watermark) bool { + return !wm.isPDF() || !wm.multiStamp() +} + +func pdfFormContent(w io.Writer, pageNr int, wm *Watermark) error { + cs := wm.pdfRes[wm.Page].content + if wm.multiStamp() { + maxStampPageNr := len(wm.pdfRes) + i := pageNr + if pageNr > maxStampPageNr { + i = maxStampPageNr + } + cs = wm.pdfRes[i].content + } + sc := wm.Scale + if !wm.ScaleAbs { + sc = wm.bb.Width() / float64(wm.width) + } + + // Scale & translate into origin + + m1 := identMatrix + m1[0][0] = sc + m1[1][1] = sc + + m2 := identMatrix + m2[2][0] = -wm.bb.LL.X * wm.ScaleEff + m2[2][1] = -wm.bb.LL.Y * wm.ScaleEff + + m := m1.multiply(m2) + + fmt.Fprintf(w, "%.2f %.2f %.2f %.2f %.2f %.2f cm ", m[0][0], m[0][1], m[1][0], m[1][1], m[2][0], m[2][1]) + + _, err := w.Write(cs) + return err +} + +func imageFormContent(w io.Writer, wm *Watermark) { + fmt.Fprintf(w, "q %f 0 0 %f 0 0 cm /Im0 Do Q", wm.bb.Width(), wm.bb.Height()) // TODO dont need Q +} + +func formContent(w io.Writer, pageNr int, wm *Watermark) error { + switch true { + case wm.isPDF(): + return pdfFormContent(w, pageNr, wm) + case wm.isImage(): + imageFormContent(w, wm) + } + return nil +} + +func setupTextDescriptor(wm *Watermark) TextDescriptor { + // Set horizontal alignment. + var hAlign HAlignment + if wm.HAlign == nil { + // Use alignment implied by anchor. + _, _, hAlign, _ = anchorPosAndAlign(wm.Pos, RectForDim(0, 0)) + } else { + // Use manual alignment. + hAlign = *wm.HAlign + } + + // Set effective position and vertical alignment. + x, y, _, vAlign := anchorPosAndAlign(BottomLeft, wm.vp) + td := wm.textDescriptor() + td.X, td.Y, td.HAlign, td.VAlign, td.FontKey = x, y, hAlign, vAlign, "F1" + + // Set margins. + td.MLeft = float64(wm.MLeft) + td.MRight = float64(wm.MRight) + td.MTop = float64(wm.MTop) + td.MBot = float64(wm.MBot) + + // Set border. + td.BorderWidth = float64(wm.BorderWidth) + td.BorderStyle = wm.BorderStyle + if wm.BorderColor != nil { + td.ShowBorder = true + td.BorderCol = *wm.BorderColor + } + return td +} + +func drawBoundingBox(b bytes.Buffer, wm *Watermark, bb *Rectangle) { + urx := bb.UR.X + ury := bb.UR.Y + if wm.isPDF() { + sc := wm.Scale + if !wm.ScaleAbs { + sc = bb.Width() / float64(wm.width) + } + urx /= sc + ury /= sc + } + fmt.Fprintf(&b, "[]0 d 2 w %.2f %.2f m %.2f %.2f l %.2f %.2f l %.2f %.2f l s ", + bb.LL.X, bb.LL.Y, + urx, bb.LL.Y, + urx, ury, + bb.LL.X, ury, + ) +} + +func (ctx *Context) createForm(pageNr int, wm *Watermark, withBB bool) error { + var b bytes.Buffer + + if wm.isImage() || wm.isPDF() { + wm.calcBoundingBox(pageNr) + } else { + td := setupTextDescriptor(wm) + // Render td into b and return the bounding box. + wm.bb = WriteMultiLine(&b, wm.vp, nil, td) + } + + // The forms bounding box is dependent on the page dimensions. + bb := wm.bb + + if cachedForm(wm) || pageNr > len(wm.pdfRes) { + // Use cached form. + ir, ok := wm.fCache[*bb.Rectangle] + if ok { + wm.form = ir + return nil + } + } + + if wm.isImage() || wm.isPDF() { + if err := formContent(&b, pageNr, wm); err != nil { + return err + } + } + + ir, err := ctx.createFormResDict(pageNr, wm) + if err != nil { + return err + } + + bbox := bb.CroppedCopy(0) + bbox.Translate(-bb.LL.X, -bb.LL.Y) + + // Paint bounding box + if withBB { + drawBoundingBox(b, wm, bbox) + } + + sd := StreamDict{ + Dict: Dict( + map[string]Object{ + "Type": Name("XObject"), + "Subtype": Name("Form"), + "BBox": bbox.Array(), + "Matrix": NewNumberArray(1, 0, 0, 1, 0, 0), + "OC": *wm.ocg, + "Resources": *ir, + }, + ), + Content: b.Bytes(), + FilterPipeline: []PDFFilter{{Name: filter.Flate, DecodeParms: nil}}, + } + + sd.InsertName("Filter", filter.Flate) + + if err = sd.Encode(); err != nil { + return err + } + + ir, err = ctx.IndRefForNewObject(sd) + if err != nil { + return err + } + + wm.form = ir + + if cachedForm(wm) || pageNr >= len(wm.pdfRes) { + // Cache form. + wm.fCache[*wm.bb.Rectangle] = ir + } + + return nil +} + +func (ctx *Context) createExtGStateForStamp(opacity float64) (*IndirectRef, error) { + d := Dict( + map[string]Object{ + "Type": Name("ExtGState"), + "CA": Float(opacity), + "ca": Float(opacity), + }, + ) + + return ctx.IndRefForNewObject(d) +} + +func (ctx *Context) insertPageResourcesForWM(pageDict Dict, wm *Watermark, gsID, xoID string) error { + resourceDict := Dict( + map[string]Object{ + "ExtGState": Dict(map[string]Object{gsID: *wm.extGState}), + "XObject": Dict(map[string]Object{xoID: *wm.form}), + }, + ) + + pageDict.Insert("Resources", resourceDict) + + return nil +} + +func (ctx *Context) updatePageResourcesForWM(resDict Dict, wm *Watermark, gsID, xoID *string) error { + o, ok := resDict.Find("ExtGState") + if !ok { + resDict.Insert("ExtGState", Dict(map[string]Object{*gsID: *wm.extGState})) + } else { + d, _ := ctx.DereferenceDict(o) + for i := 0; i < 1000; i++ { + *gsID = "GS" + strconv.Itoa(i) + if _, found := d.Find(*gsID); !found { + break + } + } + d.Insert(*gsID, *wm.extGState) + } + + o, ok = resDict.Find("XObject") + if !ok { + resDict.Insert("XObject", Dict(map[string]Object{*xoID: *wm.form})) + } else { + d, _ := ctx.DereferenceDict(o) + for i := 0; i < 1000; i++ { + *xoID = "Fm" + strconv.Itoa(i) + if _, found := d.Find(*xoID); !found { + break + } + } + d.Insert(*xoID, *wm.form) + } + + return nil +} + +func wmContent(wm *Watermark, gsID, xoID string) []byte { + m := wm.calcTransformMatrix() + insertOCG := " /Artifact <>BDC q %.2f %.2f %.2f %.2f %.2f %.2f cm /%s gs /%s Do Q EMC " + var b bytes.Buffer + fmt.Fprintf(&b, insertOCG, m[0][0], m[0][1], m[1][0], m[1][1], m[2][0], m[2][1], gsID, xoID) + return b.Bytes() +} + +func (ctx *Context) insertPageContentsForWM(pageDict Dict, wm *Watermark, gsID, xoID string) error { + sd, _ := ctx.NewStreamDictForBuf(wmContent(wm, gsID, xoID)) + if err := sd.Encode(); err != nil { + return err + } + + ir, err := ctx.IndRefForNewObject(*sd) + if err != nil { + return err + } + + pageDict.Insert("Contents", *ir) + + return nil +} + +func (ctx *Context) updatePageContentsForWM(obj Object, wm *Watermark, gsID, xoID string) error { + var entry *XRefTableEntry + var objNr int + + ir, ok := obj.(IndirectRef) + if ok { + objNr = ir.ObjectNumber.Value() + if wm.objs[objNr] { + // wm already applied to this content stream. + return nil + } + genNr := ir.GenerationNumber.Value() + entry, _ = ctx.FindTableEntry(objNr, genNr) + obj = entry.Object + } + + switch o := obj.(type) { + + case StreamDict: + + err := patchContentForWM(&o, gsID, xoID, wm, true) + if err != nil { + return err + } + + entry.Object = o + wm.objs[objNr] = true + + case Array: + + // Get stream dict for first element. + o1 := o[0] + ir, _ := o1.(IndirectRef) + objNr = ir.ObjectNumber.Value() + genNr := ir.GenerationNumber.Value() + entry, _ := ctx.FindTableEntry(objNr, genNr) + sd, _ := (entry.Object).(StreamDict) + + if len(o) == 1 || !wm.OnTop { + + if wm.objs[objNr] { + // wm already applied to this content stream. + return nil + } + + err := patchContentForWM(&sd, gsID, xoID, wm, true) + if err != nil { + return err + } + entry.Object = sd + wm.objs[objNr] = true + return nil + } + + if wm.objs[objNr] { + // wm already applied to this content stream. + } else { + // Patch first content stream. + err := patchFirstContentForWM(&sd) + if err != nil { + return err + } + entry.Object = sd + wm.objs[objNr] = true + } + + // Patch last content stream. + o1 = o[len(o)-1] + + ir, _ = o1.(IndirectRef) + objNr = ir.ObjectNumber.Value() + if wm.objs[objNr] { + // wm already applied to this content stream. + return nil + } + + genNr = ir.GenerationNumber.Value() + entry, _ = ctx.FindTableEntry(objNr, genNr) + sd, _ = (entry.Object).(StreamDict) + + err := patchContentForWM(&sd, gsID, xoID, wm, false) + if err != nil { + return err + } + + entry.Object = sd + wm.objs[objNr] = true + } + + return nil +} + +func viewPort(a *InheritedPageAttrs) *Rectangle { + visibleRegion := a.mediaBox + if a.cropBox != nil { + visibleRegion = a.cropBox + } + return visibleRegion +} + +func (ctx *Context) addPageWatermark(i int, wm *Watermark) error { + if i > ctx.PageCount { + return errors.Errorf("pdfcpu: invalid page number: %d", i) + } + + log.Debug.Printf("addPageWatermark page:%d\n", i) + if wm.Update { + log.Debug.Println("Updating") + if _, err := ctx.removePageWatermark(i); err != nil { + return err + } + } + + consolidateRes := false + d, inhPAttrs, err := ctx.PageDict(i, consolidateRes) + if err != nil { + return err + } + + wm.vp = viewPort(inhPAttrs) + + if err = ctx.createForm(i, wm, stampWithBBox); err != nil { + return err + } + + wm.pageRot = float64(inhPAttrs.rotate) + + log.Debug.Printf("\n%s\n", wm) + + gsID := "GS0" + xoID := "Fm0" + + if inhPAttrs.resources == nil { + err = ctx.insertPageResourcesForWM(d, wm, gsID, xoID) + } else { + err = ctx.updatePageResourcesForWM(inhPAttrs.resources, wm, &gsID, &xoID) + d.Update("Resources", inhPAttrs.resources) + } + if err != nil { + return err + } + + obj, found := d.Find("Contents") + if !found { + return ctx.insertPageContentsForWM(d, wm, gsID, xoID) + } + + return ctx.updatePageContentsForWM(obj, wm, gsID, xoID) +} + +func patchContentForWM(sd *StreamDict, gsID, xoID string, wm *Watermark, saveGState bool) error { + err := sd.Decode() + if err == filter.ErrUnsupportedFilter { + log.Info.Println("unsupported filter: unable to patch content with watermark.") + return nil + } + if err != nil { + return err + } + + bb := wmContent(wm, gsID, xoID) + + if wm.OnTop { + if saveGState { + sd.Content = append([]byte("q "), sd.Content...) + } + sd.Content = append(sd.Content, []byte(" Q")...) + sd.Content = append(sd.Content, bb...) + } else { + sd.Content = append(bb, sd.Content...) + } + + return sd.Encode() +} + +func patchFirstContentForWM(sd *StreamDict) error { + err := sd.Decode() + if err == filter.ErrUnsupportedFilter { + log.Info.Println("unsupported filter: unable to patch content with watermark.") + return nil + } + if err != nil { + return err + } + + sd.Content = append([]byte("q "), sd.Content...) + + return sd.Encode() +} + +func (ctx *Context) createResourcesForWMMap(m map[int]*Watermark, ocgIndRef, extGStateIndRef *IndirectRef, onTop bool, opacity float64) (map[string]*[]int, error) { + fm := map[string]*[]int{} + for i, wm := range m { + wm.ocg = ocgIndRef + wm.extGState = extGStateIndRef + wm.OnTop = onTop + wm.Opacity = opacity + if wm.isText() { + if font.IsUserFont(wm.FontName) { + // Dummy call in order to setup used glyphs. + WriteMultiLine(new(bytes.Buffer), RectForFormat("A4"), nil, setupTextDescriptor(wm)) + } + ii, found := fm[wm.FontName] + if !found { + fm[wm.FontName] = &[]int{i} + } else { + *ii = append(*ii, i) + } + continue + } + if wm.isImage() { + if err := ctx.createImageResForWM(wm); err != nil { + return nil, err + } + continue + } + if err := ctx.createPDFResForWM(wm); err != nil { + return nil, err + } + } + return fm, nil +} + +// AddWatermarksMap adds watermarks in m to corresponding pages. +func (ctx *Context) AddWatermarksMap(m map[int]*Watermark) error { + var ( + onTop bool + opacity float64 + ) + for _, wm := range m { + onTop = wm.OnTop + opacity = wm.Opacity + break + } + + ocgIndRef, err := ctx.prepareOCPropertiesInRoot(onTop) + if err != nil { + return err + } + + extGStateIndRef, err := ctx.createExtGStateForStamp(opacity) + if err != nil { + return err + } + + fm, err := ctx.createResourcesForWMMap(m, ocgIndRef, extGStateIndRef, onTop, opacity) + if err != nil { + return err + } + + for k, v := range fm { + // TODO Take existing font dicts into account. + ir, err := createFontDict(ctx.XRefTable, k) + if err != nil { + return err + } + for _, pageNr := range *v { + m[pageNr].font = ir + } + } + + for k, wm := range m { + if err := ctx.addPageWatermark(k, wm); err != nil { + return err + } + } + + ctx.EnsureVersionForWriting() + return nil +} + +// AddWatermarks adds watermarks to all pages selected. +func (ctx *Context) AddWatermarks(selectedPages IntSet, wm *Watermark) error { + log.Debug.Printf("AddWatermarks wm:\n%s\n", wm) + var err error + if wm.ocg, err = ctx.prepareOCPropertiesInRoot(wm.OnTop); err != nil { + return err + } + + if err = ctx.createResourcesForWM(wm); err != nil { + return err + } + + if wm.extGState, err = ctx.createExtGStateForStamp(wm.Opacity); err != nil { + return err + } + + if selectedPages == nil || len(selectedPages) == 0 { + selectedPages = IntSet{} + for i := 1; i <= ctx.PageCount; i++ { + selectedPages[i] = true + } + } + + for k, v := range selectedPages { + if v { + if err = ctx.addPageWatermark(k, wm); err != nil { + return err + } + } + } + + ctx.EnsureVersionForWriting() + return nil +} + +func (ctx *Context) removeResDictEntry(d *Dict, entry string, ids []string, i int) error { + o, ok := d.Find(entry) + if !ok { + return errors.Errorf("pdfcpu: page %d: corrupt resource dict", i) + } + + d1, err := ctx.DereferenceDict(o) + if err != nil { + return err + } + + for _, id := range ids { + o, ok := d1.Find(id) + if ok { + err = ctx.deleteObject(o) + if err != nil { + return err + } + d1.Delete(id) + } + } + + if d1.Len() == 0 { + d.Delete(entry) + } + + return nil +} + +func (ctx *Context) removeExtGStates(d *Dict, ids []string, i int) error { + return ctx.removeResDictEntry(d, "ExtGState", ids, i) +} + +func (ctx *Context) removeForms(d *Dict, ids []string, i int) error { + return ctx.removeResDictEntry(d, "XObject", ids, i) +} + +func removeArtifacts(sd *StreamDict, i int) (ok bool, extGStates []string, forms []string, err error) { + err = sd.Decode() + if err == filter.ErrUnsupportedFilter { + log.Info.Printf("unsupported filter: unable to patch content with watermark for page %d\n", i) + return false, nil, nil, nil + } + if err != nil { + return false, nil, nil, err + } + + var patched bool + + // Watermarks may begin or end the content stream. + + for { + s := string(sd.Content) + beg := strings.Index(s, "/Artifact <>BDC") + if beg < 0 { + break + } + + end := strings.Index(s[beg:], "EMC") + if end < 0 { + break + } + + // Check for usage of resources. + t := s[beg : beg+end] + + i := strings.Index(t, "/GS") + if i > 0 { + j := i + 3 + k := strings.Index(t[j:], " gs") + if k > 0 { + extGStates = append(extGStates, "GS"+t[j:j+k]) + } + } + + i = strings.Index(t, "/Fm") + if i > 0 { + j := i + 3 + k := strings.Index(t[j:], " Do") + if k > 0 { + forms = append(forms, "Fm"+t[j:j+k]) + } + } + + // TODO Remove whitespace until 0x0a + sd.Content = append(sd.Content[:beg], sd.Content[beg+end+3:]...) + patched = true + } + + if patched { + err = sd.Encode() + } + + return patched, extGStates, forms, err +} + +func (ctx *Context) removeArtifactsFromPage(sd *StreamDict, resDict *Dict, i int) (bool, error) { + // Remove watermark artifacts and locate id's + // of used extGStates and forms. + ok, extGStates, forms, err := removeArtifacts(sd, i) + if err != nil { + return false, err + } + if !ok { + return false, nil + } + + // Remove obsolete extGStates from page resource dict. + err = ctx.removeExtGStates(resDict, extGStates, i) + if err != nil { + return false, err + } + + // Remove obsolete extGStatesforms from page resource dict. + return true, ctx.removeForms(resDict, forms, i) +} + +func (ctx *Context) locatePageContentAndResourceDict(i int) (Object, Dict, error) { + consolidateRes := false + d, _, err := ctx.PageDict(i, consolidateRes) + if err != nil { + return nil, nil, err + } + + o, found := d.Find("Resources") + if !found { + return nil, nil, errors.Errorf("pdfcpu: page %d: no resource dict found\n", i) + } + + resDict, err := ctx.DereferenceDict(o) + if err != nil { + return nil, nil, err + } + + o, found = d.Find("Contents") + if !found { + return nil, nil, errors.Errorf("pdfcpu: page %d: no page watermark found", i) + } + + return o, resDict, nil +} + +func (ctx *Context) removePageWatermark(i int) (bool, error) { + o, resDict, err := ctx.locatePageContentAndResourceDict(i) + if err != nil { + return false, err + } + + found := false + var entry *XRefTableEntry + + ir, ok := o.(IndirectRef) + if ok { + objNr := ir.ObjectNumber.Value() + genNr := ir.GenerationNumber.Value() + entry, _ = ctx.FindTableEntry(objNr, genNr) + o = entry.Object + } + + switch o := o.(type) { + + case StreamDict: + ok, err := ctx.removeArtifactsFromPage(&o, &resDict, i) + if err != nil { + return false, err + } + if !found && ok { + found = true + } + entry.Object = o + + case Array: + // Get stream dict for first element. + o1 := o[0] + ir, _ := o1.(IndirectRef) + objNr := ir.ObjectNumber.Value() + genNr := ir.GenerationNumber.Value() + entry, _ := ctx.FindTableEntry(objNr, genNr) + sd, _ := (entry.Object).(StreamDict) + + ok, err := ctx.removeArtifactsFromPage(&sd, &resDict, i) + if err != nil { + return false, err + } + if !found && ok { + found = true + entry.Object = sd + } + + if len(o) > 1 { + // Get stream dict for last element. + o1 := o[len(o)-1] + ir, _ := o1.(IndirectRef) + objNr = ir.ObjectNumber.Value() + genNr := ir.GenerationNumber.Value() + entry, _ := ctx.FindTableEntry(objNr, genNr) + sd, _ := (entry.Object).(StreamDict) + + ok, err = ctx.removeArtifactsFromPage(&sd, &resDict, i) + if err != nil { + return false, err + } + if !found && ok { + found = true + entry.Object = sd + } + } + + } + + /* + Supposedly the form needs a PieceInfo in order to be recognized by Acrobat like so: + + + + + >>> + >>> + + */ + + return found, nil +} + +func (ctx *Context) locateOCGs() (Array, error) { + rootDict, err := ctx.Catalog() + if err != nil { + return nil, err + } + + o, ok := rootDict.Find("OCProperties") + if !ok { + return nil, errNoWatermark + } + + d, err := ctx.DereferenceDict(o) + if err != nil { + return nil, err + } + + o, found := d.Find("OCGs") + if !found { + return nil, errNoWatermark + } + + return ctx.DereferenceArray(o) +} + +// RemoveWatermarks removes watermarks for all pages selected. +func (ctx *Context) RemoveWatermarks(selectedPages IntSet) error { + log.Debug.Printf("RemoveWatermarks\n") + + a, err := ctx.locateOCGs() + if err != nil { + return err + } + + found := false + + for _, o := range a { + d, err := ctx.DereferenceDict(o) + if err != nil { + return err + } + + if o == nil { + continue + } + + if *d.Type() != "OCG" { + continue + } + + n := d.StringEntry("Name") + if n == nil { + continue + } + + if *n != "Background" && *n != "Watermark" { + continue + } + + found = true + break + } + + if !found { + return errNoWatermark + } + + var removedSmth bool + + for k, v := range selectedPages { + if !v { + continue + } + + ok, err := ctx.removePageWatermark(k) + if err != nil { + return err + } + + if ok { + removedSmth = true + } + } + + if !removedSmth { + return errNoWatermark + } + + return nil +} + +func detectArtifacts(sd *StreamDict) (bool, error) { + if err := sd.Decode(); err != nil { + return false, err + } + // Watermarks may begin or end the content stream. + i := strings.Index(string(sd.Content), "/Artifact <>BDC") + return i >= 0, nil +} + +func (ctx *Context) findPageWatermarks(pageDictIndRef *IndirectRef) (bool, error) { + d, err := ctx.DereferenceDict(*pageDictIndRef) + if err != nil { + return false, err + } + + o, found := d.Find("Contents") + if !found { + return false, errNoContent + } + + var entry *XRefTableEntry + + ir, ok := o.(IndirectRef) + if ok { + objNr := ir.ObjectNumber.Value() + genNr := ir.GenerationNumber.Value() + entry, _ = ctx.FindTableEntry(objNr, genNr) + o = entry.Object + } + + switch o := o.(type) { + + case StreamDict: + return detectArtifacts(&o) + + case Array: + // Get stream dict for first element. + o1 := o[0] + ir, _ := o1.(IndirectRef) + objNr := ir.ObjectNumber.Value() + genNr := ir.GenerationNumber.Value() + entry, _ := ctx.FindTableEntry(objNr, genNr) + sd, _ := (entry.Object).(StreamDict) + ok, err := detectArtifacts(&sd) + if err != nil { + return false, err + } + if ok { + return true, nil + } + + if len(o) > 1 { + // Get stream dict for last element. + o1 := o[len(o)-1] + ir, _ := o1.(IndirectRef) + objNr = ir.ObjectNumber.Value() + genNr := ir.GenerationNumber.Value() + entry, _ := ctx.FindTableEntry(objNr, genNr) + sd, _ := (entry.Object).(StreamDict) + return detectArtifacts(&sd) + } + + } + + return false, nil +} + +func (ctx *Context) detectPageTreeWatermarks(root *IndirectRef) error { + d, err := ctx.DereferenceDict(*root) + if err != nil { + return err + } + + kids := d.ArrayEntry("Kids") + if kids == nil { + return nil + } + + for _, o := range kids { + + if ctx.Watermarked { + return nil + } + + if o == nil { + continue + } + + // Dereference next page node dict. + ir, ok := o.(IndirectRef) + if !ok { + return errors.Errorf("pdfcpu: detectPageTreeWatermarks: corrupt page node dict") + } + + pageNodeDict, err := ctx.DereferenceDict(ir) + if err != nil { + return err + } + + switch *pageNodeDict.Type() { + + case "Pages": + // Recurse over sub pagetree. + if err := ctx.detectPageTreeWatermarks(&ir); err != nil { + return err + } + + case "Page": + found, err := ctx.findPageWatermarks(&ir) + if err != nil { + return err + } + if found { + ctx.Watermarked = true + return nil + } + + } + } + + return nil +} + +// DetectPageTreeWatermarks checks xRefTable's page tree for watermarks +// and records the result to xRefTable.Watermarked. +func (ctx *Context) DetectPageTreeWatermarks() error { + root, err := ctx.Pages() + if err != nil { + return err + } + return ctx.detectPageTreeWatermarks(root) +} + +// DetectWatermarks checks ctx for watermarks +// and records the result to xRefTable.Watermarked. +func (ctx *Context) DetectWatermarks() error { + a, err := ctx.locateOCGs() + if err != nil { + if err == errNoWatermark { + ctx.Watermarked = false + return nil + } + return err + } + + found := false + + for _, o := range a { + d, err := ctx.DereferenceDict(o) + if err != nil { + return err + } + + if o == nil { + continue + } + + if *d.Type() != "OCG" { + continue + } + + n := d.StringEntry("Name") + if n == nil { + continue + } + + if *n != "Background" && *n != "Watermark" { + continue + } + + found = true + break + } + + if !found { + ctx.Watermarked = false + return nil + } + + return ctx.DetectPageTreeWatermarks() +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/stats.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/stats.go new file mode 100644 index 0000000..b6980a7 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/stats.go @@ -0,0 +1,133 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import "github.com/pdfcpu/pdfcpu/pkg/log" + +// The PDF root object fields. +const ( + RootVersion = iota + RootExtensions + RootPageLabels + RootNames + RootDests + RootViewerPrefs + RootPageLayout + RootPageMode + RootOutlines + RootThreads + RootOpenAction + RootAA + RootURI + RootAcroForm + RootMetadata + RootStructTreeRoot + RootMarkInfo + RootLang + RootSpiderInfo + RootOutputIntents + RootPieceInfo + RootOCProperties + RootPerms + RootLegal + RootRequirements + RootCollection + RootNeedsRendering +) + +// The PDF page object fields. +const ( + PageLastModified = iota + PageResources + PageMediaBox + PageCropBox + PageBleedBox + PageTrimBox + PageArtBox + PageBoxColorInfo + PageContents + PageRotate + PageGroup + PageThumb + PageB + PageDur + PageTrans + PageAnnots + PageAA + PageMetadata + PagePieceInfo + PageStructParents + PageID + PagePZ + PageSeparationInfo + PageTabs + PageTemplateInstantiated + PagePresSteps + PageUserUnit + PageVP +) + +// PDFStats is a container for stats. +type PDFStats struct { + // Used root attributes + rootAttrs IntSet + // Used page attributes + pageAttrs IntSet +} + +// NewPDFStats returns a new PDFStats object. +func NewPDFStats() PDFStats { + return PDFStats{rootAttrs: IntSet{}, pageAttrs: IntSet{}} +} + +// AddRootAttr adds the occurrence of a field with given name to the rootAttrs set. +func (stats PDFStats) AddRootAttr(name int) { + stats.rootAttrs[name] = true +} + +// UsesRootAttr returns true if a field with given name is contained in the rootAttrs set. +func (stats PDFStats) UsesRootAttr(name int) bool { + return stats.rootAttrs[name] +} + +// AddPageAttr adds the occurrence of a field with given name to the pageAttrs set. +func (stats PDFStats) AddPageAttr(name int) { + stats.pageAttrs[name] = true +} + +// UsesPageAttr returns true if a field with given name is contained in the pageAttrs set. +func (stats PDFStats) UsesPageAttr(name int) bool { + return stats.pageAttrs[name] +} + +// ValidationTimingStats prints processing time stats for validation. +func ValidationTimingStats(dur1, dur2, dur float64) { + log.Stats.Println("Timing:") + log.Stats.Printf("read : %6.3fs %4.1f%%\n", dur1, dur1/dur*100) + log.Stats.Printf("validate : %6.3fs %4.1f%%\n", dur2, dur2/dur*100) + log.Stats.Printf("total processing time: %6.3fs\n\n", dur) +} + +// TimingStats prints processing time stats for an operation. +func TimingStats(op string, durRead, durVal, durOpt, durWrite, durTotal float64) { + log.Stats.Println("Timing:") + log.Stats.Printf("read : %6.3fs %4.1f%%\n", durRead, durRead/durTotal*100) + log.Stats.Printf("validate : %6.3fs %4.1f%%\n", durVal, durVal/durTotal*100) + log.Stats.Printf("optimize : %6.3fs %4.1f%%\n", durOpt, durOpt/durTotal*100) + log.Stats.Printf("%-21s: %6.3fs %4.1f%%\n", op, durWrite, durWrite/durTotal*100) + log.Stats.Printf("total processing time: %6.3fs\n\n", durTotal) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/streamdict.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/streamdict.go new file mode 100644 index 0000000..b0ac4f9 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/streamdict.go @@ -0,0 +1,312 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "io/ioutil" + + "github.com/pdfcpu/pdfcpu/pkg/filter" + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +// PDFFilter represents a PDF stream filter object. +type PDFFilter struct { + Name string + DecodeParms Dict +} + +// StreamDict represents a PDF stream dict object. +type StreamDict struct { + Dict + StreamOffset int64 + StreamLength *int64 + StreamLengthObjNr *int + FilterPipeline []PDFFilter + Raw []byte // Encoded + Content []byte // Decoded + IsPageContent bool +} + +// NewStreamDict creates a new PDFStreamDict for given PDFDict, stream offset and length. +func NewStreamDict(d Dict, streamOffset int64, streamLength *int64, streamLengthObjNr *int, filterPipeline []PDFFilter) StreamDict { + return StreamDict{ + d, + streamOffset, + streamLength, + streamLengthObjNr, + filterPipeline, + nil, + nil, + false, + } +} + +// Clone returns a clone of sd. +func (sd StreamDict) Clone() Object { + sd1 := sd + sd1.Dict = sd.Dict.Clone().(Dict) + pl := make([]PDFFilter, len(sd.FilterPipeline)) + for k, v := range sd.FilterPipeline { + f := PDFFilter{} + f.Name = v.Name + if f.DecodeParms != nil { + f.DecodeParms = v.DecodeParms.Clone().(Dict) + } + pl[k] = f + } + sd1.FilterPipeline = pl + return sd1 +} + +// HasSoleFilterNamed returns true if sd has a +// filterPipeline with 1 filter named filterName. +func (sd StreamDict) HasSoleFilterNamed(filterName string) bool { + fpl := sd.FilterPipeline + if fpl == nil || len(fpl) != 1 { + return false + } + return fpl[0].Name == filterName +} + +// ObjectStreamDict represents a object stream dictionary. +type ObjectStreamDict struct { + StreamDict + Prolog []byte + ObjCount int + FirstObjOffset int + ObjArray Array +} + +// NewObjectStreamDict creates a new ObjectStreamDict object. +func NewObjectStreamDict() *ObjectStreamDict { + sd := StreamDict{Dict: NewDict()} + sd.Insert("Type", Name("ObjStm")) + sd.Insert("Filter", Name(filter.Flate)) + sd.FilterPipeline = []PDFFilter{{Name: filter.Flate, DecodeParms: nil}} + return &ObjectStreamDict{StreamDict: sd} +} + +func parmsForFilter(d Dict) map[string]int { + m := map[string]int{} + + if d == nil { + return m + } + + for k, v := range d { + + i, ok := v.(Integer) + if ok { + m[k] = i.Value() + continue + } + + // Encode boolean values: false -> 0, true -> 1 + b, ok := v.(Boolean) + if ok { + m[k] = 0 + if b.Value() { + m[k] = 1 + } + continue + } + + } + + return m +} + +// Encode applies sd's filter pipeline to sd.Content in order to produce sd.Raw. +func (sd *StreamDict) Encode() error { + // No filter specified, nothing to encode. + if sd.FilterPipeline == nil { + log.Trace.Println("encodeStream: returning uncompressed stream.") + sd.Raw = sd.Content + streamLength := int64(len(sd.Raw)) + sd.StreamLength = &streamLength + sd.Update("Length", Integer(streamLength)) + return nil + } + + var b, c io.Reader + b = bytes.NewReader(sd.Content) + + // Apply each filter in the pipeline to result of preceding filter. + for _, f := range sd.FilterPipeline { + if f.DecodeParms != nil { + log.Trace.Printf("encodeStream: encoding filter:%s\ndecodeParms:%s\n", f.Name, f.DecodeParms) + } else { + log.Trace.Printf("encodeStream: encoding filter:%s\n", f.Name) + } + + // Make parms map[string]int + parms := parmsForFilter(f.DecodeParms) + + fi, err := filter.NewFilter(f.Name, parms) + if err != nil { + return err + } + + c, err = fi.Encode(b) + if err != nil { + return err + } + + b = c + } + + var err error + if sd.Raw, err = ioutil.ReadAll(c); err != nil { + return err + } + streamLength := int64(len(sd.Raw)) + sd.StreamLength = &streamLength + sd.Update("Length", Integer(streamLength)) + + return nil +} + +// Decode applies sd's filter pipeline to sd.Raw in order to produce sd.Content. +func (sd *StreamDict) Decode() error { + if sd.Content != nil { + // This stream has already been decoded. + return nil + } + + // No filter specified, nothing to decode. + if sd.FilterPipeline == nil { + sd.Content = sd.Raw + log.Trace.Printf("decodedStream returning %d(#%02x)bytes: \n%s\n", len(sd.Content), len(sd.Content), hex.Dump(sd.Content)) + return nil + } + + //fmt.Printf("decodedStream before:\n%s\n", hex.Dump(sd.Raw)) + + var b, c io.Reader + b = bytes.NewReader(sd.Raw) + + // Apply each filter in the pipeline to result of preceding filter. + for _, f := range sd.FilterPipeline { + + if f.DecodeParms != nil { + log.Trace.Printf("decodeStream: decoding filter:%s\ndecodeParms:%s\n", f.Name, f.DecodeParms) + } else { + log.Trace.Printf("decodeStream: decoding filter:%s\n", f.Name) + } + + // make parms map[string]int + parms := parmsForFilter(f.DecodeParms) + + if f.Name == filter.CCITTFax { + // x/image/ccitt needs the optional decode parameter "Rows" + // if not available we supply the image "Height". + _, ok := parms["Rows"] + if !ok { + ip := sd.IntEntry("Height") + if ip == nil { + return errors.New("pdfcpu: ccitt: \"Height\" required") + } + parms["Rows"] = *ip + } + } + + fi, err := filter.NewFilter(f.Name, parms) + if err != nil { + return err + } + + c, err = fi.Decode(b) + if err != nil { + return err + } + + //fmt.Printf("decodedStream after:%s\n%s\n", f.Name, hex.Dump(c.Bytes())) + b = c + } + + var err error + if sd.Content, err = ioutil.ReadAll(c); err != nil { + return err + } + + return nil +} + +// IndexedObject returns the object at given index from a ObjectStreamDict. +func (osd *ObjectStreamDict) IndexedObject(index int) (Object, error) { + if osd.ObjArray == nil { + return nil, errors.Errorf("IndexedObject(%d): object not available", index) + } + return osd.ObjArray[index], nil +} + +// AddObject adds another object to this object stream. +// Relies on decoded content! +func (osd *ObjectStreamDict) AddObject(objNumber int, entry *XRefTableEntry) error { + offset := len(osd.Content) + s := "" + if osd.ObjCount > 0 { + s = " " + } + s = s + fmt.Sprintf("%d %d", objNumber, offset) + osd.Prolog = append(osd.Prolog, []byte(s)...) + pdfString := entry.Object.PDFString() + osd.Content = append(osd.Content, []byte(pdfString)...) + osd.ObjCount++ + log.Trace.Printf("AddObject end : ObjCount:%d prolog = <%s> Content = <%s>\n", osd.ObjCount, osd.Prolog, osd.Content) + return nil +} + +// Finalize prepares the final content of the objectstream. +func (osd *ObjectStreamDict) Finalize() { + osd.Content = append(osd.Prolog, osd.Content...) + osd.FirstObjOffset = len(osd.Prolog) + log.Trace.Printf("Finalize : firstObjOffset:%d Content = <%s>\n", osd.FirstObjOffset, osd.Content) +} + +// XRefStreamDict represents a cross reference stream dictionary. +type XRefStreamDict struct { + StreamDict + Size int + Objects []int + W [3]int + PreviousOffset *int64 +} + +// NewXRefStreamDict creates a new PDFXRefStreamDict object. +func NewXRefStreamDict(ctx *Context) *XRefStreamDict { + sd := StreamDict{Dict: NewDict()} + sd.Insert("Type", Name("XRef")) + sd.Insert("Filter", Name(filter.Flate)) + sd.FilterPipeline = []PDFFilter{{Name: filter.Flate, DecodeParms: nil}} + sd.Insert("Root", *ctx.Root) + if ctx.Info != nil { + sd.Insert("Info", *ctx.Info) + } + if ctx.ID != nil { + sd.Insert("ID", ctx.ID) + } + if ctx.Encrypt != nil && ctx.EncKey != nil { + sd.Insert("Encrypt", *ctx.Encrypt) + } + return &XRefStreamDict{StreamDict: sd} +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/string.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/string.go new file mode 100644 index 0000000..db29ced --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/string.go @@ -0,0 +1,250 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bytes" + "strconv" + "strings" + "unicode/utf8" + + "github.com/pkg/errors" +) + +// NewStringSet returns a new StringSet for slice. +func NewStringSet(slice []string) StringSet { + strSet := StringSet{} + if slice == nil { + return strSet + } + for _, s := range slice { + strSet[s] = true + } + return strSet +} + +// Convert a 1,2 or 3 digit unescaped octal string into the corresponding byte value. +func byteForOctalString(octalBytes string) (b byte) { + i, _ := strconv.ParseInt(octalBytes, 8, 64) + return byte(i) +} + +// Escape applies all defined escape sequences to s. +func Escape(s string) (*string, error) { + + var b bytes.Buffer + + for i := 0; i < len(s); i++ { + + c := s[i] + + switch c { + case 0x0A: + c = 'n' + case 0x0D: + c = 'r' + case 0x09: + c = 't' + case 0x08: + c = 'b' + case 0x0C: + c = 'f' + case '\\', '(', ')': + default: + b.WriteByte(c) + continue + } + + b.WriteByte('\\') + b.WriteByte(c) + } + + s1 := b.String() + + return &s1, nil +} + +func escaped(c byte) (bool, byte) { + + switch c { + case 'n': + c = 0x0A + case 'r': + c = 0x0D + case 't': + c = 0x09 + case 'b': + c = 0x08 + case 'f': + c = 0x0C + case '(', ')': + case '0', '1', '2', '3', '4', '5', '6', '7': + return true, c + } + + return false, c +} + +func regularChar(c byte, esc bool) bool { + return c != 0x5c && !esc +} + +// Unescape resolves all escape sequences of s. +func Unescape(s string) ([]byte, error) { + + var esc bool + var longEol bool + var octalCode string + var b bytes.Buffer + + for i := 0; i < len(s); i++ { + + c := s[i] + + if longEol { + esc = false + longEol = false + // c is completing a 0x5C0D0A line break. + if c == 0x0A { + continue + } + } + + if regularChar(c, esc) { + b.WriteByte(c) + continue + } + + if c == 0x5c { // '\' + if !esc { // Start escape sequence. + esc = true + } else { // Escaped \ + if len(octalCode) > 0 { + return nil, errors.Errorf("Unescape: illegal \\ in octal code sequence detected %X", octalCode) + } + b.WriteByte(c) + esc = false + } + continue + } + + // escaped = true && any other than \ + + if len(octalCode) > 0 { + if !strings.ContainsRune("01234567", rune(c)) { + return nil, errors.Errorf("Unescape: illegal octal sequence detected %X", octalCode) + } + octalCode = octalCode + string(c) + if len(octalCode) == 3 { + b.WriteByte(byteForOctalString(octalCode)) + octalCode = "" + esc = false + } + continue + } + + // Ignore \eol line breaks. + if c == 0x0A { + esc = false + continue + } + + if c == 0x0D { + longEol = true + continue + } + + if !strings.ContainsRune("nrtbf()01234567", rune(c)) { + return nil, errors.Errorf("Unescape: illegal escape sequence \\%c detected", c) + } + + var octal bool + octal, c = escaped(c) + if octal { + octalCode = octalCode + string(c) + continue + } + + b.WriteByte(c) + esc = false + } + + return b.Bytes(), nil +} + +// This is a patched version of strings.FieldsFunc that also returns empty fields. +func fieldsFunc(s string, f func(rune) bool) []string { + // A span is used to record a slice of s of the form s[start:end]. + // The start index is inclusive and the end index is exclusive. + type span struct { + start int + end int + } + spans := make([]span, 0, 32) + + // Find the field start and end indices. + wasField := false + fromIndex := 0 + for i, rune := range s { + if f(rune) { + if wasField { + spans = append(spans, span{start: fromIndex, end: i}) + wasField = false + } else { + spans = append(spans, span{}) + } + } else { + if !wasField { + fromIndex = i + wasField = true + } + } + } + + // Last field might end at EOF. + if wasField { + spans = append(spans, span{fromIndex, len(s)}) + } + + // Create strings from recorded field indices. + a := make([]string, len(spans)) + for i, span := range spans { + a[i] = s[span.start:span.end] + } + + return a +} + +// UTF8ToCP1252 converts UTF-8 to CP1252. +func UTF8ToCP1252(s string) string { + bb := []byte{} + for _, r := range s { + bb = append(bb, byte(r)) + } + return string(bb) +} + +// CP1252ToUTF8 converts CP1252 to UTF-8. +func CP1252ToUTF8(s string) string { + utf8Buf := make([]byte, utf8.UTFMax) + bb := []byte{} + for i := 0; i < len(s); i++ { + n := utf8.EncodeRune(utf8Buf, rune(s[i])) + bb = append(bb, utf8Buf[:n]...) + } + return string(bb) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types.go new file mode 100644 index 0000000..78bd9f3 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types.go @@ -0,0 +1,502 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bytes" + "encoding/hex" + "fmt" + "strconv" + + "github.com/pdfcpu/pdfcpu/pkg/types" +) + +// Supported line delimiters +const ( + EolLF = "\x0A" + EolCR = "\x0D" + EolCRLF = "\x0D\x0A" +) + +// FreeHeadGeneration is the predefined generation number for the head of the free list. +const FreeHeadGeneration = 65535 + +// ByteSize represents the various terms for storage space. +type ByteSize float64 + +// Storage space terms. +const ( + _ = iota // ignore first value by assigning to blank identifier + KB ByteSize = 1 << (10 * iota) + MB + GB +) + +func (b ByteSize) String() string { + + switch { + case b >= GB: + return fmt.Sprintf("%.2f GB", b/GB) + case b >= MB: + return fmt.Sprintf("%.1f MB", b/MB) + case b >= KB: + return fmt.Sprintf("%.0f KB", b/KB) + } + + return fmt.Sprintf("%f Bytes", b) +} + +// IntSet is a set of integers. +type IntSet map[int]bool + +// StringSet is a set of strings. +type StringSet map[string]bool + +// Object defines an interface for all Objects. +type Object interface { + fmt.Stringer + Clone() Object + PDFString() string +} + +// Boolean represents a PDF boolean object. +type Boolean bool + +// Clone returns a clone of boolean. +func (boolean Boolean) Clone() Object { + return boolean +} + +func (boolean Boolean) String() string { + return fmt.Sprintf("%v", bool(boolean)) +} + +// PDFString returns a string representation as found in and written to a PDF file. +func (boolean Boolean) PDFString() string { + return boolean.String() +} + +// Value returns a bool value for this PDF object. +func (boolean Boolean) Value() bool { + return bool(boolean) +} + +/////////////////////////////////////////////////////////////////////////////////// + +// Float represents a PDF float object. +type Float float64 + +// Clone returns a clone of f. +func (f Float) Clone() Object { + return f +} + +func (f Float) String() string { + // Use a precision of 2 for logging readability. + return fmt.Sprintf("%.2f", float64(f)) +} + +// PDFString returns a string representation as found in and written to a PDF file. +func (f Float) PDFString() string { + // The max precision encountered so far has been 12 (fontType3 fontmatrix components). + return strconv.FormatFloat(f.Value(), 'f', 12, 64) +} + +// Value returns a float64 value for this PDF object. +func (f Float) Value() float64 { + return float64(f) +} + +/////////////////////////////////////////////////////////////////////////////////// + +// Integer represents a PDF integer object. +type Integer int + +// Clone returns a clone of i. +func (i Integer) Clone() Object { + return i +} + +func (i Integer) String() string { + return strconv.Itoa(int(i)) +} + +// PDFString returns a string representation as found in and written to a PDF file. +func (i Integer) PDFString() string { + return i.String() +} + +// Value returns an int value for this PDF object. +func (i Integer) Value() int { + return int(i) +} + +/////////////////////////////////////////////////////////////////////////////////// + +// Point represents a user space location. +type Point struct { + X, Y float64 +} + +// Rectangle represents a rectangular region in userspace. +type Rectangle struct { + *types.Rectangle +} + +func (r Rectangle) equals(r2 Rectangle) bool { + return r.LL == r2.LL && r.UR == r2.UR +} + +// FitsWithin returns true if rectangle r fits within rectangle r2. +func (r Rectangle) FitsWithin(r2 *Rectangle) bool { + return r.Width() <= r2.Width() && r.Height() <= r2.Height() +} + +// ScaledWidth returns the width for given height according to r's aspect ratio. +func (r Rectangle) ScaledWidth(h float64) float64 { + return r.AspectRatio() * h +} + +// ScaledHeight returns the height for given width according to r's aspect ratio. +func (r Rectangle) ScaledHeight(w float64) float64 { + return w / r.AspectRatio() +} + +// Dimensions returns r's dimensions. +func (r Rectangle) Dimensions() Dim { + return Dim{r.Width(), r.Height()} +} + +// Translate moves r by dx and dy. +func (r *Rectangle) Translate(dx, dy float64) { + r.LL.Translate(dx, dy) + r.UR.Translate(dx, dy) +} + +// Array returns the PDF representation of a rectangle. +func (r Rectangle) Array() Array { + return NewNumberArray(r.LL.X, r.LL.Y, r.UR.X, r.UR.Y) +} + +// CroppedCopy returns a copy of r with applied margin.. +func (r Rectangle) CroppedCopy(margin float64) *Rectangle { + return Rect( + r.LL.X+margin, + r.LL.Y+margin, + r.UR.X-margin, + r.UR.Y-margin, + ) +} + +func (r Rectangle) formatToInches() string { + return fmt.Sprintf("(%3.2f, %3.2f, %3.2f, %3.2f) w=%.2f h=%.2f ar=%.2f", + r.LL.X*userSpaceToInch, + r.LL.Y*userSpaceToInch, + r.UR.X*userSpaceToInch, + r.UR.Y*userSpaceToInch, + r.Width()*userSpaceToInch, + r.Height()*userSpaceToInch, + r.AspectRatio()) +} + +func (r Rectangle) formatToCentimetres() string { + return fmt.Sprintf("(%3.2f, %3.2f, %3.2f, %3.2f) w=%.2f h=%.2f ar=%.2f", + r.LL.X*userSpaceToCm, + r.LL.Y*userSpaceToCm, + r.UR.X*userSpaceToCm, + r.UR.Y*userSpaceToCm, + r.Width()*userSpaceToCm, + r.Height()*userSpaceToCm, + r.AspectRatio()) +} + +func (r Rectangle) formatToMillimetres() string { + return fmt.Sprintf("(%3.2f, %3.2f, %3.2f, %3.2f) w=%.2f h=%.2f ar=%.2f", + r.LL.X*userSpaceToMm, + r.LL.Y*userSpaceToMm, + r.UR.X*userSpaceToMm, + r.UR.Y*userSpaceToMm, + r.Width()*userSpaceToMm, + r.Height()*userSpaceToMm, + r.AspectRatio()) +} + +// Format returns r's details converted into unit. +func (r Rectangle) Format(unit DisplayUnit) string { + switch unit { + case INCHES: + return r.formatToInches() + case CENTIMETRES: + return r.formatToCentimetres() + case MILLIMETRES: + return r.formatToMillimetres() + } + return r.String() +} + +// Rect returns a new rectangle for given lower left and upper right corners. +func Rect(llx, lly, urx, ury float64) *Rectangle { + return &Rectangle{types.NewRectangle(llx, lly, urx, ury)} +} + +// RectForArray returns a new rectangle for given Array. +func RectForArray(a Array) *Rectangle { + return Rect( + a[0].(Float).Value(), + a[1].(Float).Value(), + a[2].(Float).Value(), + a[3].(Float).Value(), + ) +} + +// RectForDim returns a new rectangle for given dimensions. +func RectForDim(width, height float64) *Rectangle { + return Rect(0.0, 0.0, width, height) +} + +// RectForWidthAndHeight returns a new rectangle for given dimensions. +func RectForWidthAndHeight(llx, lly, width, height float64) *Rectangle { + return Rect(llx, lly, llx+width, lly+height) +} + +// RectForFormat returns a new rectangle for given format. +func RectForFormat(f string) *Rectangle { + d := PaperSize[f] + return RectForDim(d.Width, d.Height) +} + +/////////////////////////////////////////////////////////////////////////////////// + +// Name represents a PDF name object. +type Name string + +// Clone returns a clone of nameObject. +func (nameObject Name) Clone() Object { + return nameObject +} + +func (nameObject Name) String() string { + return fmt.Sprintf("%s", string(nameObject)) +} + +// PDFString returns a string representation as found in and written to a PDF file. +func (nameObject Name) PDFString() string { + s := " " + if len(nameObject) > 0 { + s = string(nameObject) + } + return fmt.Sprintf("/%s", s) +} + +// Value returns a string value for this PDF object. +func (nameObject Name) Value() string { + + s := string(nameObject) + var b bytes.Buffer + + for i := 0; i < len(s); { + c := s[i] + if c != '#' { + b.WriteByte(c) + i++ + continue + } + + // # detected, next 2 chars have to exist. + // This gets checked during parsing. + s1 := s[i+1 : i+3] + b1, _ := hex.DecodeString(s1) + b.WriteByte(b1[0]) + i += 3 + } + + return b.String() +} + +/////////////////////////////////////////////////////////////////////////////////// + +// StringLiteral represents a PDF string literal object. +type StringLiteral string + +// Clone returns a clone of stringLiteral. +func (stringliteral StringLiteral) Clone() Object { + return stringliteral +} + +func (stringliteral StringLiteral) String() string { + return fmt.Sprintf("(%s)", string(stringliteral)) +} + +// PDFString returns a string representation as found in and written to a PDF file. +func (stringliteral StringLiteral) PDFString() string { + return stringliteral.String() +} + +// Value returns a string value for this PDF object. +func (stringliteral StringLiteral) Value() string { + return string(stringliteral) +} + +/////////////////////////////////////////////////////////////////////////////////// + +// HexLiteral represents a PDF hex literal object. +type HexLiteral string + +// NewHexLiteral creates a new HexLiteral for b.. +func NewHexLiteral(b []byte) HexLiteral { + return HexLiteral(hex.EncodeToString(b)) +} + +// Clone returns a clone of hexliteral. +func (hexliteral HexLiteral) Clone() Object { + return hexliteral +} +func (hexliteral HexLiteral) String() string { + return fmt.Sprintf("<%s>", string(hexliteral)) +} + +// PDFString returns the string representation as found in and written to a PDF file. +func (hexliteral HexLiteral) PDFString() string { + return hexliteral.String() +} + +// Value returns a string value for this PDF object. +func (hexliteral HexLiteral) Value() string { + return string(hexliteral) +} + +// Bytes returns the byte representation. +func (hexliteral HexLiteral) Bytes() ([]byte, error) { + b, err := hex.DecodeString(hexliteral.Value()) + if err != nil { + return nil, err + } + return b, err +} + +/////////////////////////////////////////////////////////////////////////////////// + +// IndirectRef represents a PDF indirect object. +type IndirectRef struct { + ObjectNumber Integer + GenerationNumber Integer +} + +// NewIndirectRef returns a new PDFIndirectRef object. +func NewIndirectRef(objectNumber, generationNumber int) *IndirectRef { + return &IndirectRef{ + ObjectNumber: Integer(objectNumber), + GenerationNumber: Integer(generationNumber)} +} + +// Clone returns a clone of ir. +func (ir IndirectRef) Clone() Object { + ir2 := ir + return ir2 +} + +func (ir IndirectRef) String() string { + return fmt.Sprintf("(%s)", ir.PDFString()) +} + +// PDFString returns a string representation as found in and written to a PDF file. +func (ir IndirectRef) PDFString() string { + return fmt.Sprintf("%d %d R", ir.ObjectNumber, ir.GenerationNumber) +} + +// Equals returns true if two indirect References refer to the same object. +func (ir IndirectRef) Equals(indRef IndirectRef) bool { + return ir.ObjectNumber == indRef.ObjectNumber && + ir.GenerationNumber == indRef.GenerationNumber +} + +///////////////////////////////////////////////////////////////////////////////////// + +// DisplayUnit is the metric unit used to output paper sizes. +type DisplayUnit int + +// Options for display unit in effect. +const ( + POINTS DisplayUnit = iota + INCHES + CENTIMETRES + MILLIMETRES +) + +const ( + userSpaceToInch = float64(1) / 72 + userSpaceToCm = 2.54 / 72 + userSpaceToMm = userSpaceToCm * 10 + + inchToUserSpace = 1 / userSpaceToInch + cmToUserSpace = 1 / userSpaceToCm + mmToUserSpace = 1 / userSpaceToMm +) + +func toUserSpace(f float64, unit DisplayUnit) float64 { + switch unit { + case INCHES: + return f * inchToUserSpace + case CENTIMETRES: + return f * cmToUserSpace + case MILLIMETRES: + return f * mmToUserSpace + + } + return f +} + +// Dim represents the dimensions of a rectangular view medium +// like a PDF page, a sheet of paper or an image grid +// in user space, inches, centimetres or millimetres. +type Dim struct { + Width, Height float64 +} + +// ToInches converts d to inches. +func (d Dim) ToInches() Dim { + return Dim{d.Width * userSpaceToInch, d.Height * userSpaceToInch} +} + +// ToCentimetres converts d to centimetres. +func (d Dim) ToCentimetres() Dim { + return Dim{d.Width * userSpaceToCm, d.Height * userSpaceToCm} +} + +// ToMillimetres converts d to centimetres. +func (d Dim) ToMillimetres() Dim { + return Dim{d.Width * userSpaceToMm, d.Height * userSpaceToMm} +} + +// AspectRatio returns the relation between width and height. +func (d Dim) AspectRatio() float64 { + return d.Width / d.Height +} + +// Landscape returns true if d is in landscape mode. +func (d Dim) Landscape() bool { + return d.AspectRatio() > 1 +} + +// Portrait returns true if d is in portrait mode. +func (d Dim) Portrait() bool { + return d.AspectRatio() < 1 +} + +func (d Dim) String() string { + return fmt.Sprintf("%fx%f points", d.Width, d.Height) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/utf16.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/utf16.go new file mode 100644 index 0000000..f576586 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/utf16.go @@ -0,0 +1,167 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "encoding/hex" + "fmt" + "unicode/utf16" + "unicode/utf8" + + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +// ErrInvalidUTF16BE represents an error that gets raised for invalid UTF-16BE byte sequences. +var ErrInvalidUTF16BE = errors.New("pdfcpu: invalid UTF-16BE detected") + +// IsStringUTF16BE checks a string for Big Endian byte order BOM. +func IsStringUTF16BE(s string) bool { + s1 := fmt.Sprintf("%s", s) + ok := strings.HasPrefix(s1, "\376\377") // 0xFE 0xFF + //log.Debug.Printf("IsStringUTF16BE: <%s> returning %v\n", s1, ok) + //log.Debug.Printf("\n%s", hex.Dump([]byte(s1))) + return ok +} + +// IsUTF16BE checks for Big Endian byte order mark and valid length. +func IsUTF16BE(b []byte) bool { + if len(b) == 0 || len(b)%2 != 0 { + return false + } + // Check BOM + return b[0] == 0xFE && b[1] == 0xFF +} + +func decodeUTF16String(b []byte) (string, error) { + + //log.Debug.Printf("decodeUTF16String: begin %v\n", b) + + // We only accept big endian byte order. + if !IsUTF16BE(b) { + log.Debug.Printf("decodeUTF16String: not UTF16BE: %v\n", b) + return "", ErrInvalidUTF16BE + } + + // Strip BOM. + b = b[2:] + + // code points + u16 := make([]uint16, 0, len(b)) + + // Collect code points. + for i := 0; i < len(b); { + + //log.Debug.Printf("i=%d\n", i) + + val := (uint16(b[i]) << 8) + uint16(b[i+1]) + + if val <= 0xD7FF || val > 0xE000 && val <= 0xFFFF { + // Basic Multilingual Plane + //log.Debug.Println("decodeUTF16String: Basic Multilingual Plane detected") + u16 = append(u16, val) + i += 2 + continue + } + + // Ensure bytes needed in order to decode surrogate pair. + if i+2 >= len(b) { + return "", errors.Errorf("decodeUTF16String: corrupt UTF16BE byte length on unicode point 1: %v", b) + } + + // Ensure high surrogate is leading in possible surrogate pair. + if val >= 0xDC00 && val <= 0xDFFF { + return "", errors.Errorf("decodeUTF16String: corrupt UTF16BE on unicode point 1: %v", b) + } + + // Supplementary Planes + //log.Debug.Println("decodeUTF16String: Supplementary Planes detected") + u16 = append(u16, val) + val = (uint16(b[i+2]) << 8) + uint16(b[i+3]) + if val < 0xDC00 || val > 0xDFFF { + return "", errors.Errorf("decodeUTF16String: corrupt UTF16BE on unicode point 2: %v", b) + } + + u16 = append(u16, val) + i += 4 + } + + decb := []byte{} + utf8Buf := make([]byte, utf8.UTFMax) + + for _, rune := range utf16.Decode(u16) { + n := utf8.EncodeRune(utf8Buf, rune) + decb = append(decb, utf8Buf[:n]...) + } + + //log.Debug.Printf("decodeUTF16String: end %s\n", hex.Dump(decb)) + return string(decb), nil +} + +// DecodeUTF16String decodes a UTF16BE string from a hex string. +func DecodeUTF16String(s string) (string, error) { + return decodeUTF16String([]byte(s)) +} + +func encodeUTF16String(s string) string { + rr := utf16.Encode([]rune(s)) + bb := []byte{0xFE, 0xFF} + for _, r := range rr { + bb = append(bb, byte(r>>8), byte(r&0xFF)) + } + return string(bb) +} + +// StringLiteralToString returns the best possible string rep for a string literal. +func StringLiteralToString(s string) (string, error) { + b, err := Unescape(s) + if err != nil { + return "", err + } + + s1 := string(b) + + // Check for Big Endian UTF-16. + if IsStringUTF16BE(s1) { + return DecodeUTF16String(s1) + } + + // if no acceptable UTF16 encoding found, ensure utf8 encoding. + if !utf8.ValidString(s1) { + s1 = CP1252ToUTF8(s1) + } + return s1, nil +} + +// HexLiteralToString returns a possibly UTF16 encoded string for a hex string. +func HexLiteralToString(hexString string) (string, error) { + // Get corresponding byte slice. + b, err := hex.DecodeString(hexString) + if err != nil { + return "", err + } + + // Check for Big Endian UTF-16. + if IsUTF16BE(b) { + return decodeUTF16String(b) + } + + // if no acceptable UTF16 encoding found, just return decoded hexstring. + return string(b), nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/acroForm.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/acroForm.go new file mode 100644 index 0000000..16da198 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/acroForm.go @@ -0,0 +1,484 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateSignatureDict(xRefTable *pdf.XRefTable, o pdf.Object) error { + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + // Type, optional, name + _, err = validateNameEntry(xRefTable, d, "signatureDict", "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "Sig" }) + + // process signature dict fields. + + return err +} + +func validateAppearanceSubDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // dict of xobjects + for _, o := range d { + + err := validateXObjectStreamDict(xRefTable, o) + if err != nil { + return err + } + + } + + return nil +} + +func validateAppearanceDictEntry(xRefTable *pdf.XRefTable, o pdf.Object) error { + + // stream or dict + // single appearance stream or subdict + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Dict: + err = validateAppearanceSubDict(xRefTable, o) + + case pdf.StreamDict: + err = validateXObjectStreamDict(xRefTable, o) + + default: + err = errors.New("pdfcpu: validateAppearanceDictEntry: unsupported PDF object") + + } + + return err +} + +func validateAppearanceDict(xRefTable *pdf.XRefTable, o pdf.Object) error { + + // see 12.5.5 Appearance Streams + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + // Normal Appearance + o, ok := d.Find("N") + if !ok { + if xRefTable.ValidationMode == pdf.ValidationStrict { + return errors.New("pdfcpu: validateAppearanceDict: missing required entry \"N\"") + } + } else { + err = validateAppearanceDictEntry(xRefTable, o) + if err != nil { + return err + } + } + + // Rollover Appearance + if o, ok = d.Find("R"); ok { + err = validateAppearanceDictEntry(xRefTable, o) + if err != nil { + return err + } + } + + // Down Appearance + if o, ok = d.Find("D"); ok { + err = validateAppearanceDictEntry(xRefTable, o) + if err != nil { + return err + } + } + + return nil +} + +func validateAcroFieldDictEntries(xRefTable *pdf.XRefTable, d pdf.Dict, terminalNode bool, inFieldType *pdf.Name) (outFieldType *pdf.Name, err error) { + + dictName := "acroFieldDict" + + // FT: name, Btn,Tx,Ch,Sig + validate := func(s string) bool { return pdf.MemberOf(s, []string{"Btn", "Tx", "Ch", "Sig"}) } + fieldType, err := validateNameEntry(xRefTable, d, dictName, "FT", terminalNode && inFieldType == nil, pdf.V10, validate) + if err != nil { + return nil, err + } + + if fieldType != nil { + outFieldType = fieldType + } + + // Parent, required if this is a child in the field hierarchy. + _, err = validateIndRefEntry(xRefTable, d, dictName, "Parent", OPTIONAL, pdf.V10) + if err != nil { + return nil, err + } + + // T, optional, text string + _, err = validateStringEntry(xRefTable, d, dictName, "T", OPTIONAL, pdf.V10, nil) + if err != nil { + return nil, err + } + + // TU, optional, text string, since V1.3 + _, err = validateStringEntry(xRefTable, d, dictName, "TU", OPTIONAL, pdf.V13, nil) + if err != nil { + return nil, err + } + + // TM, optional, text string, since V1.3 + _, err = validateStringEntry(xRefTable, d, dictName, "TM", OPTIONAL, pdf.V13, nil) + if err != nil { + return nil, err + } + + // Ff, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "Ff", OPTIONAL, pdf.V10, nil) + if err != nil { + return nil, err + } + + // V, optional, various + _, err = validateEntry(xRefTable, d, dictName, "V", OPTIONAL, pdf.V10) + if err != nil { + return nil, err + } + + // DV, optional, various + _, err = validateEntry(xRefTable, d, dictName, "DV", OPTIONAL, pdf.V10) + if err != nil { + return nil, err + } + + // AA, optional, dict, since V1.2 + err = validateAdditionalActions(xRefTable, d, dictName, "AA", OPTIONAL, pdf.V14, "fieldOrAnnot") + if err != nil { + return nil, err + } + + return outFieldType, nil +} + +func validateAcroFieldParts(xRefTable *pdf.XRefTable, d pdf.Dict, inFieldType *pdf.Name) error { + // dict represents a terminal field and must have Subtype "Widget" + if _, err := validateNameEntry(xRefTable, d, "acroFieldDict", "Subtype", REQUIRED, pdf.V10, func(s string) bool { return s == "Widget" }); err != nil { + return err + } + + // Validate field dict entries. + if _, err := validateAcroFieldDictEntries(xRefTable, d, true, inFieldType); err != nil { + return err + } + + // Validate widget annotation - Validation of AA redundant because of merged acrofield with widget annotation. + _, err := validateAnnotationDict(xRefTable, d) + return err +} + +func validateAcroFieldKid(xRefTable *pdf.XRefTable, d pdf.Dict, o pdf.Object, inFieldType *pdf.Name) error { + var err error + // dict represents a non terminal field. + if d.Subtype() != nil && *d.Subtype() == "Widget" { + return errors.New("pdfcpu: validateAcroFieldKid: non terminal field can not be widget annotation") + } + + // Validate field entries. + var xInFieldType *pdf.Name + if xInFieldType, err = validateAcroFieldDictEntries(xRefTable, d, false, inFieldType); err != nil { + return err + } + + // Recurse over kids. + a, err := xRefTable.DereferenceArray(o) + if err != nil || a == nil { + return err + } + + for _, value := range a { + ir, ok := value.(pdf.IndirectRef) + if !ok { + return errors.New("pdfcpu: validateAcroFieldKid: corrupt kids array: entries must be indirect reference") + } + valid, err := xRefTable.IsValid(ir) + if err != nil { + return err + } + + if !valid { + if err = validateAcroFieldDict(xRefTable, ir, xInFieldType); err != nil { + return err + } + } + } + + return nil +} + +func validateAcroFieldDict(xRefTable *pdf.XRefTable, ir pdf.IndirectRef, inFieldType *pdf.Name) error { + d, err := xRefTable.DereferenceDict(ir) + if err != nil || d == nil { + return err + } + + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + if len(d) == 0 { + return nil + } + } + + if err := xRefTable.SetValid(ir); err != nil { + return err + } + + if o, ok := d.Find("Kids"); ok { + return validateAcroFieldKid(xRefTable, d, o, inFieldType) + } + + return validateAcroFieldParts(xRefTable, d, inFieldType) +} + +func validateAcroFormFields(xRefTable *pdf.XRefTable, o pdf.Object) error { + + a, err := xRefTable.DereferenceArray(o) + if err != nil || a == nil { + return err + } + + for _, value := range a { + + ir, ok := value.(pdf.IndirectRef) + if !ok { + return errors.New("pdfcpu: validateAcroFormFields: corrupt form field array entry") + } + + valid, err := xRefTable.IsValid(ir) + if err != nil { + return err + } + + if !valid { + if validateAcroFieldDict(xRefTable, ir, nil); err != nil { + return err + } + } + + } + + return nil +} + +func validateAcroFormCO(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // see 12.6.3 Trigger Events + // Array of indRefs to field dicts with calculation actions, since V1.3 + + // Version check + err := xRefTable.ValidateVersion("AcroFormCO", sinceVersion) + if err != nil { + return err + } + + a, err := xRefTable.DereferenceArray(o) + if err != nil || a == nil { + return err + } + + for _, o := range a { + + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return err + } + + if d == nil { + continue + } + + _, err = validateAnnotationDict(xRefTable, d) + if err != nil { + return err + } + + } + + return nil +} + +func validateAcroFormXFA(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see 12.7.8 + + o, ok := d.Find("XFA") + if !ok { + return nil + } + + // streamDict or array of text,streamDict pairs + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.StreamDict: + // no further processing + + case pdf.Array: + + i := 0 + + for _, v := range o { + + if v == nil { + return errors.New("pdfcpu: validateAcroFormXFA: array entry is nil") + } + + o, err := xRefTable.Dereference(v) + if err != nil { + return err + } + + if i%2 == 0 { + + _, ok := o.(pdf.StringLiteral) + if !ok { + return errors.New("pdfcpu: validateAcroFormXFA: even array must be a string") + } + + } else { + + _, ok := o.(pdf.StreamDict) + if !ok { + return errors.New("pdfcpu: validateAcroFormXFA: odd array entry must be a streamDict") + } + + } + + i++ + } + + default: + return errors.New("pdfcpu: validateAcroFormXFA: needs to be streamDict or array") + } + + return xRefTable.ValidateVersion("AcroFormXFA", sinceVersion) +} + +func validateQ(i int) bool { return i >= 0 && i <= 2 } + +func validateAcroFormEntryCO(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + o, ok := d.Find("CO") + if !ok { + return nil + } + + return validateAcroFormCO(xRefTable, o, sinceVersion) +} + +func validateAcroFormEntryDR(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + o, ok := d.Find("DR") + if !ok { + return nil + } + + _, err := validateResourceDict(xRefTable, o) + + return err +} + +func validateAcroForm(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 12.7.2 Interactive Form Dictionary + + d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "AcroForm", OPTIONAL, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + // Version check + err = xRefTable.ValidateVersion("AcroForm", sinceVersion) + if err != nil { + return err + } + + // Fields, required, array of indirect references + o, ok := d.Find("Fields") + if !ok { + return errors.New("pdfcpu: validateAcroForm: missing required entry \"Fields\"") + } + + err = validateAcroFormFields(xRefTable, o) + if err != nil { + return err + } + + dictName := "acroFormDict" + + // NeedAppearances: optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "NeedAppearances", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // SigFlags: optional, since 1.3, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "SigFlags", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // CO: arra + err = validateAcroFormEntryCO(xRefTable, d, pdf.V13) + if err != nil { + return err + } + + // DR, optional, resource dict + err = validateAcroFormEntryDR(xRefTable, d) + if err != nil { + return err + } + + // DA: optional, string + _, err = validateStringEntry(xRefTable, d, dictName, "DA", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Q: optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "Q", OPTIONAL, pdf.V10, validateQ) + if err != nil { + return err + } + + // XFA: optional, since 1.5, stream or array + return validateAcroFormXFA(xRefTable, d, sinceVersion) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/action.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/action.go new file mode 100644 index 0000000..a4f8109 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/action.go @@ -0,0 +1,929 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateGoToActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.2 Go-To Actions + + // D, required, name, byte string or array + return validateDestinationEntry(xRefTable, d, dictName, "D", REQUIRED, pdf.V10) +} + +func validateGoToRActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.3 Remote Go-To Actions + + // F, required, file specification + _, err := validateFileSpecEntry(xRefTable, d, dictName, "F", REQUIRED, pdf.V11) + if err != nil { + return err + } + + // D, required, name, byte string or array + err = validateDestinationEntry(xRefTable, d, dictName, "D", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // NewWindow, optional, boolean, since V1.2 + _, err = validateBooleanEntry(xRefTable, d, dictName, "NewWindow", OPTIONAL, pdf.V12, nil) + + return err +} + +func validateTargetDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + // table 202 + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + dictName = "targetDict" + + // R, required, name + _, err = validateNameEntry(xRefTable, d1, dictName, "R", REQUIRED, pdf.V10, func(s string) bool { return s == "P" || s == "C" }) + if err != nil { + return err + } + + // N, optional, byte string + _, err = validateStringEntry(xRefTable, d1, dictName, "N", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // P, optional, integer or byte string + err = validateIntOrStringEntry(xRefTable, d1, dictName, "P", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // A, optional, integer or text string + err = validateIntOrStringEntry(xRefTable, d1, dictName, "A", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // T, optional, target dict + return validateTargetDictEntry(xRefTable, d1, dictName, "T", OPTIONAL, pdf.V10) +} + +func validateGoToEActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.4 Embedded Go-To Actions + + // F, optional, file specification + f, err := validateFileSpecEntry(xRefTable, d, dictName, "F", OPTIONAL, pdf.V11) + if err != nil { + return err + } + + // D, required, name, byte string or array + err = validateDestinationEntry(xRefTable, d, dictName, "D", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // NewWindow, optional, boolean, since V1.2 + _, err = validateBooleanEntry(xRefTable, d, dictName, "NewWindow", OPTIONAL, pdf.V12, nil) + if err != nil { + return err + } + + // T, required unless entry F is present, target dict + return validateTargetDictEntry(xRefTable, d, dictName, "T", f == nil, pdf.V10) +} + +func validateWinDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // see table 204 + + dictName := "winDict" + + // F, required, byte string + _, err := validateStringEntry(xRefTable, d, dictName, "F", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // D, optional, byte string + _, err = validateStringEntry(xRefTable, d, dictName, "D", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // O, optional, ASCII string + _, err = validateStringEntry(xRefTable, d, dictName, "O", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // P, optional, byte string + _, err = validateStringEntry(xRefTable, d, dictName, "P", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateLaunchActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.5 + + // F, optional, file specification + _, err := validateFileSpecEntry(xRefTable, d, dictName, "F", OPTIONAL, pdf.V11) + if err != nil { + return err + } + + // Win, optional, dict + d1, err := validateDictEntry(xRefTable, d, dictName, "Win", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateWinDict(xRefTable, d1) + } + + // Mac, optional, undefined dict + + // Unix, optional, undefined dict + + return err +} + +func validateDestinationThreadEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + // The destination thread (table 205) + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o.(type) { + + case pdf.Dict, pdf.StringLiteral, pdf.Integer: + // an indRef to a thread dictionary + // or an index of the thread within the roots Threads array + // or the title of the thread as specified in its thread info dict + + default: + return errors.Errorf("validateDestinationThreadEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + return nil +} + +func validateDestinationBeadEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + // The bead in the destination thread (table 205) + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o.(type) { + + case pdf.Dict, pdf.Integer: + // an indRef to a bead dictionary of a thread in the current file + // or an index of the thread within its thread + + default: + return errors.Errorf("validateDestinationBeadEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + return nil +} + +func validateThreadActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + //see 12.6.4.6 + + // F, optional, file specification + _, err := validateFileSpecEntry(xRefTable, d, dictName, "F", OPTIONAL, pdf.V11) + if err != nil { + return err + } + + // D, required, indRef to thread dict, integer or text string. + err = validateDestinationThreadEntry(xRefTable, d, dictName, "D", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // B, optional, indRef to bead dict or integer. + return validateDestinationBeadEntry(xRefTable, d, dictName, "B", OPTIONAL, pdf.V10) +} + +func validateURIActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.7 + + // URI, required, string + _, err := validateStringEntry(xRefTable, d, dictName, "URI", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // IsMap, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "IsMap", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateSoundDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + sd, err := validateStreamDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || sd == nil { + return err + } + + dictName = "soundDict" + + // Type, optional, name + _, err = validateNameEntry(xRefTable, sd.Dict, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "Sound" }) + if err != nil { + return err + } + + // R, required, number - sampling rate + _, err = validateNumberEntry(xRefTable, sd.Dict, dictName, "R", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // C, required, integer - # of sound channels + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "C", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // B, required, integer - bits per sample value per channel + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "B", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // E, optional, name - encoding format + validateSampleDataEncoding := func(s string) bool { + return pdf.MemberOf(s, []string{"Raw", "Signed", "muLaw", "ALaw"}) + } + _, err = validateNameEntry(xRefTable, sd.Dict, dictName, "E", OPTIONAL, pdf.V10, validateSampleDataEncoding) + + return err +} + +func validateSoundActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.8 + + // Sound, required, stream dict + err := validateSoundDictEntry(xRefTable, d, dictName, "Sound", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // Volume, optional, number: -1.0 .. +1.0 + _, err = validateNumberEntry(xRefTable, d, dictName, "Volume", OPTIONAL, pdf.V10, func(f float64) bool { return -1.0 <= f && f <= 1.0 }) + if err != nil { + return err + } + + // Synchronous, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "Synchronous", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Repeat, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "Repeat", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Mix, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "Mix", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateMovieStartOrDurationEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Integer, pdf.StringLiteral: + // no further processing + + case pdf.Array: + if len(o) != 2 { + return errors.New("pdfcpu: validateMovieStartOrDurationEntry: array length <> 2") + } + } + + return nil +} + +func validateMovieActivationDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "movieActivationDict" + + // Start, optional + err := validateMovieStartOrDurationEntry(xRefTable, d, dictName, "Start", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // Duration, optional + err = validateMovieStartOrDurationEntry(xRefTable, d, dictName, "Duration", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // Rate, optional, number + _, err = validateNumberEntry(xRefTable, d, dictName, "Rate", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Volume, optional, number + _, err = validateNumberEntry(xRefTable, d, dictName, "Volume", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // ShowControls, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "ShowControls", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Mode, optional, name + validatePlayMode := func(s string) bool { + return pdf.MemberOf(s, []string{"Once", "Open", "Repeat", "Palindrome"}) + } + _, err = validateNameEntry(xRefTable, d, dictName, "Mode", OPTIONAL, pdf.V10, validatePlayMode) + if err != nil { + return err + } + + // Synchronous, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "Synchronous", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // FWScale, optional, array of 2 positive integers + _, err = validateIntegerArrayEntry(xRefTable, d, dictName, "FWScale", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + // FWPosition, optional, array of 2 numbers [0.0 .. 1.0] + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "FWPosition", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + + return err +} + +func validateMovieActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.9 + + // is a movie activation dict + err := validateMovieActivationDict(xRefTable, d) + if err != nil { + return err + } + + // Needs either Annotation or T entry but not both. + + // T, text string + _, err = validateStringEntry(xRefTable, d, dictName, "T", OPTIONAL, pdf.V10, nil) + if err == nil { + return nil + } + + // Annotation, indRef of movie annotation dict + ir, err := validateIndRefEntry(xRefTable, d, dictName, "Annotation", REQUIRED, pdf.V10) + if err != nil || ir == nil { + return err + } + + d, err = xRefTable.DereferenceDict(*ir) + if err != nil || d == nil { + return errors.New("pdfcpu: validateMovieActionDict: missing required entry \"T\" or \"Annotation\"") + } + + _, err = validateNameEntry(xRefTable, d, "annotDict", "Subtype", REQUIRED, pdf.V10, func(s string) bool { return s == "Movie" }) + + return err +} + +func validateHideActionDictEntryT(xRefTable *pdf.XRefTable, o pdf.Object) error { + + switch o := o.(type) { + + case pdf.StringLiteral: + // Ensure UTF16 correctness. + _, err := pdf.StringLiteralToString(o.Value()) + if err != nil { + return err + } + + case pdf.Dict: + // annotDict, Check for required name Subtype + _, err := validateNameEntry(xRefTable, o, "annotDict", "Subtype", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + case pdf.Array: + // mixed array of annotationDict indRefs and strings + for _, v := range o { + + o, err := xRefTable.Dereference(v) + if err != nil { + return err + } + + if o == nil { + continue + } + + switch o := o.(type) { + + case pdf.StringLiteral: + // Ensure UTF16 correctness. + _, err = pdf.StringLiteralToString(o.Value()) + if err != nil { + return err + } + + case pdf.Dict: + // annotDict, Check for required name Subtype + _, err = validateNameEntry(xRefTable, o, "annotDict", "Subtype", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + } + } + + default: + return errors.Errorf("validateHideActionDict: invalid entry \"T\"") + + } + + return nil +} + +func validateHideActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.10 + + // T, required, dict, text string or array + o, found := d.Find("T") + if !found || o == nil { + return errors.New("pdfcpu: validateHideActionDict: missing required entry \"T\"") + } + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + err = validateHideActionDictEntryT(xRefTable, o) + if err != nil { + return err + } + + // H, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "H", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateNamedActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.11 + + validate := func(s string) bool { + + if pdf.MemberOf(s, []string{"NextPage", "PrevPage", "FirstPage", "Lastpage"}) { + return true + } + + // Some known non standard named actions + if pdf.MemberOf(s, []string{"GoToPage", "GoBack", "GoForward", "Find", "Print", "Quit", "FullScreen"}) { + return true + } + + return false + } + + _, err := validateNameEntry(xRefTable, d, dictName, "N", REQUIRED, pdf.V10, validate) + + return err +} + +func validateSubmitFormActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.7.5.2 + + // F, required, URL specification + _, err := validateURLSpecEntry(xRefTable, d, dictName, "F", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // Fields, optional, array + // Each element of the array shall be either an indirect reference to a field dictionary + // or (PDF 1.3) a text string representing the fully qualified name of a field. + a, err := validateArrayEntry(xRefTable, d, dictName, "Fields", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + if a != nil { + for _, v := range a { + switch v.(type) { + case pdf.StringLiteral, pdf.IndirectRef: + // no further processing + + default: + return errors.New("pdfcpu: validateSubmitFormActionDict: unknown Fields entry") + } + } + } + + // Flags, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "Flags", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateResetFormActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.7.5.3 + + // Fields, optional, array + // Each element of the array shall be either an indirect reference to a field dictionary + // or (PDF 1.3) a text string representing the fully qualified name of a field. + a, err := validateArrayEntry(xRefTable, d, dictName, "Fields", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + if a != nil { + for _, v := range a { + switch v.(type) { + case pdf.StringLiteral, pdf.IndirectRef: + // no further processing + + default: + return errors.New("pdfcpu: validateResetFormActionDict: unknown Fields entry") + } + } + } + + // Flags, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "Flags", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateImportDataActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.7.5.4 + + // F, required, file specification + _, err := validateFileSpecEntry(xRefTable, d, dictName, "F", OPTIONAL, pdf.V11) + + return err +} + +func validateJavaScript(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool) error { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, pdf.V13) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.StringLiteral: + // Ensure UTF16 correctness. + _, err = pdf.StringLiteralToString(o.Value()) + + case pdf.HexLiteral: + // Ensure UTF16 correctness. + _, err = pdf.HexLiteralToString(o.Value()) + + case pdf.StreamDict: + // no further processing + + default: + err = errors.Errorf("validateJavaScript: invalid type\n") + + } + + return err +} + +func validateJavaScriptActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.16 + + // JS, required, text string or stream + return validateJavaScript(xRefTable, d, dictName, "JS", REQUIRED) +} + +func validateSetOCGStateActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.12 + + // State, required, array + _, err := validateArrayEntry(xRefTable, d, dictName, "State", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // PreserveRB, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "PreserveRB", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateRenditionActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.13 + + // OP or JS need to be present. + + // OP, integer + op, err := validateIntegerEntry(xRefTable, d, dictName, "OP", OPTIONAL, pdf.V15, func(i int) bool { return 0 <= i && i <= 4 }) + if err != nil { + return err + } + + // JS, text string or stream + err = validateJavaScript(xRefTable, d, dictName, "JS", op == nil) + if err != nil { + return err + } + + // R, required for OP 0 and 4, rendition object dict + required := func(op *pdf.Integer) bool { + if op == nil { + return false + } + v := op.Value() + return v == 0 || v == 4 + }(op) + + d1, err := validateDictEntry(xRefTable, d, dictName, "R", required, pdf.V15, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateRenditionDict(xRefTable, d1, pdf.V15) + if err != nil { + return err + } + } + + // AN, required for any OP 0..4, indRef of screen annotation dict + d1, err = validateDictEntry(xRefTable, d, dictName, "AN", op != nil, pdf.V10, nil) + if err != nil { + return err + } + if d1 != nil { + _, err = validateNameEntry(xRefTable, d1, dictName, "Subtype", REQUIRED, pdf.V10, func(s string) bool { return s == "Screen" }) + if err != nil { + return err + } + } + + return nil +} + +func validateTransActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.14 + + // Trans, required, transitionDict + d1, err := validateDictEntry(xRefTable, d, dictName, "Trans", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + return validateTransitionDict(xRefTable, d1) +} + +func validateGoTo3DViewActionDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.6.4.15 + + // TA, required, target annotation + d1, err := validateDictEntry(xRefTable, d, dictName, "TA", REQUIRED, pdf.V16, nil) + if err != nil { + return err + } + + _, err = validateAnnotationDict(xRefTable, d1) + if err != nil { + return err + } + + // V, required, the view to use: 3DViewDict or integer or text string or name + // TODO Validation. + _, err = validateEntry(xRefTable, d, dictName, "V", REQUIRED, pdf.V16) + + return err +} + +func validateActionDictCore(xRefTable *pdf.XRefTable, n *pdf.Name, d pdf.Dict) error { + + for k, v := range map[string]struct { + validate func(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error + sinceVersion pdf.Version + }{ + "GoTo": {validateGoToActionDict, pdf.V10}, + "GoToR": {validateGoToRActionDict, pdf.V10}, + "GoToE": {validateGoToEActionDict, pdf.V16}, + "Launch": {validateLaunchActionDict, pdf.V10}, + "Thread": {validateThreadActionDict, pdf.V10}, + "URI": {validateURIActionDict, pdf.V10}, + "Sound": {validateSoundActionDict, pdf.V12}, + "Movie": {validateMovieActionDict, pdf.V12}, + "Hide": {validateHideActionDict, pdf.V12}, + "Named": {validateNamedActionDict, pdf.V12}, + "SubmitForm": {validateSubmitFormActionDict, pdf.V10}, + "ResetForm": {validateResetFormActionDict, pdf.V12}, + "ImportData": {validateImportDataActionDict, pdf.V12}, + "JavaScript": {validateJavaScriptActionDict, pdf.V13}, + "SetOCGState": {validateSetOCGStateActionDict, pdf.V15}, + "Rendition": {validateRenditionActionDict, pdf.V15}, + "Trans": {validateTransActionDict, pdf.V15}, + "GoTo3DView": {validateGoTo3DViewActionDict, pdf.V16}, + } { + if n.Value() == k { + + err := xRefTable.ValidateVersion(k, v.sinceVersion) + if err != nil { + return err + } + + return v.validate(xRefTable, d, k) + } + } + + return errors.Errorf("validateActionDictCore: unsupported action type: %s\n", *n) +} + +func validateActionDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "actionDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "Action" }) + if err != nil { + return err + } + + // S, required, name, action Type + s, err := validateNameEntry(xRefTable, d, dictName, "S", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + err = validateActionDictCore(xRefTable, s, d) + if err != nil { + return err + } + + if o, ok := d.Find("Next"); ok { + + // either optional action dict + d, err := xRefTable.DereferenceDict(o) + if err == nil { + return validateActionDict(xRefTable, d) + } + + // or optional array of action dicts + a, err := xRefTable.DereferenceArray(o) + if err != nil { + return err + } + + for _, v := range a { + + d, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateActionDict(xRefTable, d) + if err != nil { + return err + } + } + + } + + return nil +} + +func validateRootAdditionalActions(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + return validateAdditionalActions(xRefTable, rootDict, "rootDict", "AA", required, sinceVersion, "root") +} + +func validateAdditionalActions(xRefTable *pdf.XRefTable, dict pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, source string) error { + + d, err := validateDictEntry(xRefTable, dict, dictName, entryName, required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + validateAdditionalAction := func(s, source string) bool { + + switch source { + + case "root": + if pdf.MemberOf(s, []string{"WC", "WS", "DS", "WP", "DP"}) { + return true + } + + case "page": + if pdf.MemberOf(s, []string{"O", "C"}) { + return true + } + + case "fieldOrAnnot": + // A terminal acro field may be merged with a widget annotation. + fieldOptions := []string{"K", "F", "V", "C"} + annotOptions := []string{"E", "X", "D", "U", "Fo", "Bl", "PO", "PC", "PV", "Pl"} + options := append(fieldOptions, annotOptions...) + if pdf.MemberOf(s, options) { + return true + } + + } + + return false + } + + for k, v := range d { + + if !validateAdditionalAction(k, source) { + return errors.Errorf("validateAdditionalActions: action %s not allowed for source %s", k, source) + } + + d, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateActionDict(xRefTable, d) + if err != nil { + return err + } + + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/annotations.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/annotations.go new file mode 100644 index 0000000..a5b5b33 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/annotations.go @@ -0,0 +1,1617 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + "github.com/pdfcpu/pdfcpu/pkg/log" + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateAAPLAKExtrasDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + // No documentation for this PDF-Extension - purely speculative implementation. + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + dictName = "AAPLAKExtrasDict" + + // AAPL:AKAnnotationObject, string + _, err = validateStringEntry(xRefTable, d1, dictName, "AAPL:AKAnnotationObject", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // AAPL:AKPDFAnnotationDictionary, annotationDict + ad, err := validateDictEntry(xRefTable, d1, dictName, "AAPL:AKPDFAnnotationDictionary", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateAnnotationDict(xRefTable, ad) + if err != nil { + return err + } + + return nil +} + +func validateBorderEffectDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + // see 12.5.4 + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + dictName = "borderEffectDict" + + // S, optional, name, S or C + _, err = validateNameEntry(xRefTable, d1, dictName, "S", OPTIONAL, pdf.V10, func(s string) bool { return s == "S" || s == "C" }) + if err != nil { + return err + } + + // I, optional, number in the range 0 to 2 + _, err = validateNumberEntry(xRefTable, d1, dictName, "I", OPTIONAL, pdf.V10, func(f float64) bool { return 0 <= f && f <= 2 }) // validation missing + if err != nil { + return err + } + + return nil +} + +func validateBorderStyleDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + // see 12.5.4 + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + dictName = "borderStyleDict" + + // Type, optional, name, "Border" + _, err = validateNameEntry(xRefTable, d1, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "Border" }) + if err != nil { + return err + } + + // W, optional, number, border width in points + _, err = validateNumberEntry(xRefTable, d1, dictName, "W", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // S, optional, name, border style + validate := func(s string) bool { return pdf.MemberOf(s, []string{"S", "D", "B", "I", "U", "A"}) } + _, err = validateNameEntry(xRefTable, d1, dictName, "S", OPTIONAL, pdf.V10, validate) + if err != nil { + return err + } + + // D, optional, dash array + _, err = validateNumberArrayEntry(xRefTable, d1, dictName, "D", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) <= 2 }) + + return err +} + +func validateIconFitDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + // see table 247 + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + dictName = "iconFitDict" + + // SW, optional, name, A,B,S,N + validate := func(s string) bool { return pdf.MemberOf(s, []string{"A", "B", "S", "N"}) } + _, err = validateNameEntry(xRefTable, d1, dictName, "SW", OPTIONAL, pdf.V10, validate) + if err != nil { + return err + } + + // S, optional, name, A,P + _, err = validateNameEntry(xRefTable, d1, dictName, "S", OPTIONAL, pdf.V10, func(s string) bool { return s == "A" || s == "P" }) + if err != nil { + return err + } + + // A,optional, array of 2 numbers between 0.0 and 1.0 + _, err = validateNumberArrayEntry(xRefTable, d1, dictName, "A", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // FB, optional, bool, since V1.5 + _, err = validateBooleanEntry(xRefTable, d1, dictName, "FB", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + return nil +} + +func validateAppearanceCharacteristicsDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + // see 12.5.6.19 + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + dictName = "appCharDict" + + // R, optional, integer + _, err = validateIntegerEntry(xRefTable, d1, dictName, "R", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // BC, optional, array of numbers, len=0,1,3,4 + _, err = validateNumberArrayEntry(xRefTable, d1, dictName, "BC", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // BG, optional, array of numbers between 0.0 and 0.1, len=0,1,3,4 + _, err = validateNumberArrayEntry(xRefTable, d1, dictName, "BG", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // CA, optional, text string + _, err = validateStringEntry(xRefTable, d1, dictName, "CA", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // RC, optional, text string + _, err = validateStringEntry(xRefTable, d1, dictName, "RC", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // AC, optional, text string + _, err = validateStringEntry(xRefTable, d1, dictName, "AC", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // I, optional, stream dict + _, err = validateStreamDictEntry(xRefTable, d1, dictName, "I", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // RI, optional, stream dict + _, err = validateStreamDictEntry(xRefTable, d1, dictName, "RI", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // IX, optional, stream dict + _, err = validateStreamDictEntry(xRefTable, d1, dictName, "IX", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // IF, optional, icon fit dict, + err = validateIconFitDictEntry(xRefTable, d1, dictName, "IF", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // TP, optional, integer 0..6 + _, err = validateIntegerEntry(xRefTable, d1, dictName, "TP", OPTIONAL, pdf.V10, func(i int) bool { return 0 <= i && i <= 6 }) + + return err +} + +func validateAnnotationDictText(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.4 + + // Open, optional, boolean + _, err := validateBooleanEntry(xRefTable, d, dictName, "Open", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Name, optional, name + _, err = validateNameEntry(xRefTable, d, dictName, "Name", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // State, optional, text string, since V1.5 + validate := func(s string) bool { return pdf.MemberOf(s, []string{"None", "Unmarked"}) } + state, err := validateStringEntry(xRefTable, d, dictName, "State", OPTIONAL, pdf.V15, validate) + if err != nil { + return err + } + + // StateModel, text string, since V1.5 + validate = func(s string) bool { return pdf.MemberOf(s, []string{"Marked", "Review"}) } + _, err = validateStringEntry(xRefTable, d, dictName, "StateModel", state != nil, pdf.V15, validate) + + return err +} + +func validateActionOrDestination(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, sinceVersion pdf.Version) error { + + // The action that shall be performed when this item is activated. + d1, err := validateDictEntry(xRefTable, d, dictName, "A", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + return validateActionDict(xRefTable, d1) + } + + // A destination that shall be displayed when this item is activated. + obj, err := validateEntry(xRefTable, d, dictName, "Dest", OPTIONAL, sinceVersion) + if err != nil || obj == nil { + return err + } + + return validateDestination(xRefTable, obj) +} + +func validateURIActionDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + dictName = "URIActionDict" + + // Type, optional, name + _, err = validateNameEntry(xRefTable, d1, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "Action" }) + if err != nil { + return err + } + + // S, required, name, action Type + _, err = validateNameEntry(xRefTable, d1, dictName, "S", REQUIRED, pdf.V10, func(s string) bool { return s == "URI" }) + if err != nil { + return err + } + + return validateURIActionDict(xRefTable, d1, dictName) +} + +func validateAnnotationDictLink(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.5 + + // A or Dest, required either or + err := validateActionOrDestination(xRefTable, d, dictName, pdf.V11) + if err != nil { + return err + } + + // H, optional, name, since V1.2 + _, err = validateNameEntry(xRefTable, d, dictName, "H", OPTIONAL, pdf.V12, nil) + if err != nil { + return err + } + + // PA, optional, URI action dict, since V1.3 + err = validateURIActionDictEntry(xRefTable, d, dictName, "PA", OPTIONAL, pdf.V13) + if err != nil { + return err + } + + // QuadPoints, optional, number array, len=8, since V1.6 + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "QuadPoints", OPTIONAL, pdf.V16, func(a pdf.Array) bool { return len(a) == 8 }) + if err != nil { + return err + } + + // BS, optional, border style dict, since V1.6 + sinceVersion := pdf.V16 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + + return validateBorderStyleDict(xRefTable, d, dictName, "BS", OPTIONAL, sinceVersion) +} + +func validateAnnotationDictFreeTextPart1(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, sinceVersion pdf.Version) error { + + // DA, required, string + _, err := validateStringEntry(xRefTable, d, dictName, "DA", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // Q, optional, integer, since V1.4, 0,1,2 + sinceVersion = pdf.V14 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + _, err = validateIntegerEntry(xRefTable, d, dictName, "Q", OPTIONAL, sinceVersion, func(i int) bool { return 0 <= i && i <= 2 }) + if err != nil { + return err + } + + // RC, optional, text string or text stream, since V1.5 + sinceVersion = pdf.V15 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V14 + } + err = validateStringOrStreamEntry(xRefTable, d, dictName, "RC", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // DS, optional, text string, since V1.5 + _, err = validateStringEntry(xRefTable, d, dictName, "DS", OPTIONAL, pdf.V15, nil) + if err != nil { + return err + } + + // CL, optional, number array, since V1.6, len: 4 or 6 + sinceVersion = pdf.V16 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V14 + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "CL", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 4 || len(a) == 6 }) + + return err +} + +func validateAnnotationDictFreeTextPart2(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, sinceVersion pdf.Version) error { + + // IT, optional, name, since V1.6 + sinceVersion = pdf.V16 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V14 + } + validate := func(s string) bool { + return pdf.MemberOf(s, []string{"FreeText", "FreeTextCallout", "FreeTextTypeWriter", "FreeTextTypewriter"}) + } + _, err := validateNameEntry(xRefTable, d, dictName, "IT", OPTIONAL, sinceVersion, validate) + if err != nil { + return err + } + + // BE, optional, border effect dict, since V1.6 + err = validateBorderEffectDictEntry(xRefTable, d, dictName, "BE", OPTIONAL, pdf.V15) + if err != nil { + return err + } + + // RD, optional, rectangle, since V1.6 + sinceVersion = pdf.V16 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V14 + } + _, err = validateRectangleEntry(xRefTable, d, dictName, "RD", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // BS, optional, border style dict, since V1.6 + sinceVersion = pdf.V16 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + err = validateBorderStyleDict(xRefTable, d, dictName, "BS", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // LE, optional, name, since V1.6 + sinceVersion = pdf.V16 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V14 + } + _, err = validateNameEntry(xRefTable, d, dictName, "LE", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateAnnotationDictFreeText(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.6 + + err := validateAnnotationDictFreeTextPart1(xRefTable, d, dictName, pdf.V13) + if err != nil { + return err + } + + return validateAnnotationDictFreeTextPart2(xRefTable, d, dictName, pdf.V13) +} + +func validateEntryMeasure(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, "Measure", required, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateMeasureDict(xRefTable, d1, sinceVersion) + } + + return err +} + +func validateCP(s string) bool { return s == "Inline" || s == "Top" } + +func validateAnnotationDictLine(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.7 + + // L, required, array of numbers, len:4 + _, err := validateNumberArrayEntry(xRefTable, d, dictName, "L", REQUIRED, pdf.V10, func(a pdf.Array) bool { return len(a) == 4 }) + if err != nil { + return err + } + + // BS, optional, border style dict + err = validateBorderStyleDict(xRefTable, d, dictName, "BS", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // LE, optional, name array, since V1.4, len:2 + sinceVersion := pdf.V14 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + _, err = validateNameArrayEntry(xRefTable, d, dictName, "LE", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + // IC, optional, number array, since V1.4, len:0,1,3,4 + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "IC", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // LLE, optional, number, since V1.6, >0 + lle, err := validateNumberEntry(xRefTable, d, dictName, "LLE", OPTIONAL, pdf.V16, func(f float64) bool { return f > 0 }) + if err != nil { + return err + } + + // LL, required if LLE present, number, since V1.6 + _, err = validateNumberEntry(xRefTable, d, dictName, "LL", lle != nil, pdf.V16, nil) + if err != nil { + return err + } + + // Cap, optional, bool, since V1.6 + _, err = validateBooleanEntry(xRefTable, d, dictName, "Cap", OPTIONAL, pdf.V16, nil) + if err != nil { + return err + } + + // IT, optional, name, since V1.6 + _, err = validateNameEntry(xRefTable, d, dictName, "IT", OPTIONAL, pdf.V16, nil) + if err != nil { + return err + } + + // LLO, optionl, number, since V1.7, >0 + _, err = validateNumberEntry(xRefTable, d, dictName, "LLO", OPTIONAL, pdf.V17, func(f float64) bool { return f > 0 }) + if err != nil { + return err + } + + // CP, optional, name, since V1.7 + _, err = validateNameEntry(xRefTable, d, dictName, "CP", OPTIONAL, pdf.V17, validateCP) + if err != nil { + return err + } + + // Measure, optional, measure dict, since V1.7 + err = validateEntryMeasure(xRefTable, d, dictName, OPTIONAL, pdf.V17) + if err != nil { + return err + } + + // CO, optional, number array, since V1.7, len=2 + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "CO", OPTIONAL, pdf.V17, func(a pdf.Array) bool { return len(a) == 2 }) + + return err +} + +func validateAnnotationDictCircleOrSquare(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.8 + + // BS, optional, border style dict + err := validateBorderStyleDict(xRefTable, d, dictName, "BS", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // IC, optional, array, since V1.4 + sinceVersion := pdf.V14 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "IC", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // BE, optional, border effect dict, since V1.5 + err = validateBorderEffectDictEntry(xRefTable, d, dictName, "BE", OPTIONAL, pdf.V15) + if err != nil { + return err + } + + // RD, optional, rectangle, since V1.5 + _, err = validateRectangleEntry(xRefTable, d, dictName, "RD", OPTIONAL, pdf.V15, nil) + + return err +} + +func validateEntryIT(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool, sinceVersion pdf.Version) error { + + // IT, optional, name, since V1.6 + validateIntent := func(s string) bool { + + if xRefTable.Version() == pdf.V16 { + return s == "PolygonCloud" + } + + if xRefTable.Version() == pdf.V17 { + if pdf.MemberOf(s, []string{"PolygonCloud", "PolyLineDimension", "PolygonDimension"}) { + return true + } + } + + return false + + } + + _, err := validateNameEntry(xRefTable, d, dictName, "IT", required, sinceVersion, validateIntent) + + return err +} + +func validateAnnotationDictPolyLine(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.9 + + // Vertices, required, array of numbers + _, err := validateNumberArrayEntry(xRefTable, d, dictName, "Vertices", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // LE, optional, array of 2 names, meaningful only for polyline annotations. + if dictName == "PolyLine" { + _, err = validateNameArrayEntry(xRefTable, d, dictName, "LE", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + } + + // BS, optional, border style dict + err = validateBorderStyleDict(xRefTable, d, dictName, "BS", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // IC, optional, array of numbers [0.0 .. 1.0], len:1,3,4 + ensureArrayLength := func(a pdf.Array, lengths ...int) bool { + for _, length := range lengths { + if len(a) == length { + return true + } + } + return false + } + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "IC", OPTIONAL, pdf.V14, func(a pdf.Array) bool { return ensureArrayLength(a, 1, 3, 4) }) + if err != nil { + return err + } + + // BE, optional, border effect dict, meaningful only for polygon annotations + if dictName == "Polygon" { + err = validateBorderEffectDictEntry(xRefTable, d, dictName, "BE", OPTIONAL, pdf.V10) + if err != nil { + return err + } + } + + return validateEntryIT(xRefTable, d, dictName, OPTIONAL, pdf.V16) +} + +func validateTextMarkupAnnotation(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.10 + + // QuadPoints, required, number array, len: a multiple of 8 + _, err := validateNumberArrayEntry(xRefTable, d, dictName, "QuadPoints", REQUIRED, pdf.V10, func(a pdf.Array) bool { return len(a)%8 == 0 }) + + return err +} + +func validateAnnotationDictStamp(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.12 + + // Name, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Name", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateAnnotationDictCaret(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.11 + + // RD, optional, rectangle, since V1.5 + _, err := validateRectangleEntry(xRefTable, d, dictName, "RD", OPTIONAL, pdf.V15, nil) + if err != nil { + return err + } + + // Sy, optional, name + _, err = validateNameEntry(xRefTable, d, dictName, "Sy", OPTIONAL, pdf.V10, func(s string) bool { return s == "P" || s == "None" }) + + return err +} + +func validateAnnotationDictInk(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.13 + + // InkList, required, array of stroked path arrays + _, err := validateArrayArrayEntry(xRefTable, d, dictName, "InkList", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // BS, optional, border style dict + return validateBorderStyleDict(xRefTable, d, dictName, "BS", OPTIONAL, pdf.V10) +} + +func validateAnnotationDictPopup(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.14 + + // Parent, optional, dict indRef + ir, err := validateIndRefEntry(xRefTable, d, dictName, "Parent", OPTIONAL, pdf.V10) + if err != nil { + return err + } + if ir != nil { + d1, err := xRefTable.DereferenceDict(*ir) + if err != nil || d1 == nil { + return err + } + } + + // Open, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "Open", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateAnnotationDictFileAttachment(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.15 + + // FS, required, file specification + _, err := validateFileSpecEntry(xRefTable, d, dictName, "FS", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // Name, optional, name + _, err = validateNameEntry(xRefTable, d, dictName, "Name", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateAnnotationDictSound(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.16 + + // Sound, required, stream dict + err := validateSoundDictEntry(xRefTable, d, dictName, "Sound", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // Name, optional, name + _, err = validateNameEntry(xRefTable, d, dictName, "Name", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateMovieDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "movieDict" + + // F, required, file specification + _, err := validateFileSpecEntry(xRefTable, d, dictName, "F", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // Aspect, optional, integer array, length 2 + _, err = validateIntegerArrayEntry(xRefTable, d, dictName, "Ascpect", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + // Rotate, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "Rotate", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Poster, optional boolean or stream + return validateBooleanOrStreamEntry(xRefTable, d, dictName, "Poster", OPTIONAL, pdf.V10) +} + +func validateAnnotationDictMovie(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.17 Movie Annotations + // 13.4 Movies + // The features described in this sub-clause are obsolescent and their use is no longer recommended. + // They are superseded by the general multimedia framework described in 13.2, “Multimedia.” + + // T, optional, text string + _, err := validateStringEntry(xRefTable, d, dictName, "T", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Movie, required, movie dict + d1, err := validateDictEntry(xRefTable, d, dictName, "Movie", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + err = validateMovieDict(xRefTable, d1) + if err != nil { + return err + } + + // A, optional, boolean or movie activation dict + o, found := d.Find("A") + + if found { + + o, err = xRefTable.Dereference(o) + if err != nil { + return err + } + + if o != nil { + switch o := o.(type) { + case pdf.Boolean: + // no further processing + + case pdf.Dict: + err = validateMovieActivationDict(xRefTable, o) + if err != nil { + return err + } + } + } + + } + + return nil +} + +func validateAnnotationDictWidget(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.19 + + // H, optional, name + validate := func(s string) bool { return pdf.MemberOf(s, []string{"N", "I", "O", "P", "T", "A"}) } + _, err := validateNameEntry(xRefTable, d, dictName, "H", OPTIONAL, pdf.V10, validate) + if err != nil { + return err + } + + // MK, optional, dict + // An appearance characteristics dictionary that shall be used in constructing + // a dynamic appearance stream specifying the annotation’s visual presentation on the page.dict + err = validateAppearanceCharacteristicsDictEntry(xRefTable, d, dictName, "MK", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // A, optional, dict, since V1.1 + // An action that shall be performed when the annotation is activated. + d1, err := validateDictEntry(xRefTable, d, dictName, "A", OPTIONAL, pdf.V11, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateActionDict(xRefTable, d1) + if err != nil { + return err + } + } + + // AA, optional, dict, since V1.2 + // An additional-actions dictionary defining the annotation’s behaviour in response to various trigger events. + err = validateAdditionalActions(xRefTable, d, dictName, "AA", OPTIONAL, pdf.V12, "fieldOrAnnot") + if err != nil { + return err + } + + // BS, optional, border style dict, since V1.2 + // A border style dictionary specifying the width and dash pattern + // that shall be used in drawing the annotation’s border. + validateBorderStyleDict(xRefTable, d, dictName, "BS", OPTIONAL, pdf.V12) + if err != nil { + return err + } + + // Parent, dict, required if one of multiple children in a field. + // An indirect reference to the widget annotation’s parent field. + _, err = validateIndRefEntry(xRefTable, d, dictName, "Parent", OPTIONAL, pdf.V10) + + return err +} + +func validateAnnotationDictScreen(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.18 + + // T, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "T", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // MK, optional, appearance characteristics dict + err = validateAppearanceCharacteristicsDictEntry(xRefTable, d, dictName, "MK", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // A, optional, action dict, since V1.0 + d1, err := validateDictEntry(xRefTable, d, dictName, "A", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateActionDict(xRefTable, d1) + if err != nil { + return err + } + } + + // AA, optional, additional-actions dict, since V1.2 + return validateAdditionalActions(xRefTable, d, dictName, "AA", OPTIONAL, pdf.V12, "fieldOrAnnot") +} + +func validateAnnotationDictPrinterMark(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.20 + + // MN, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "MN", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // F, required integer, since V1.1, annotation flags + _, err = validateIntegerEntry(xRefTable, d, dictName, "F", REQUIRED, pdf.V11, nil) + if err != nil { + return err + } + + // AP, required, appearance dict, since V1.2 + return validateAppearDictEntry(xRefTable, d, dictName, REQUIRED, pdf.V12) +} + +func validateAnnotationDictTrapNet(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.21 + + // LastModified, optional, date + _, err := validateDateEntry(xRefTable, d, dictName, "LastModified", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // Version, optional, array + _, err = validateArrayEntry(xRefTable, d, dictName, "Version", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // AnnotStates, optional, array of names + _, err = validateNameArrayEntry(xRefTable, d, dictName, "AnnotStates", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // FontFauxing, optional, font dict array + validateFontDictArray := func(a pdf.Array) bool { + + var retValue bool + + for _, v := range a { + + if v == nil { + continue + } + + d, err := xRefTable.DereferenceDict(v) + if err != nil { + return false + } + + if d == nil { + continue + } + + if d.Type() == nil || *d.Type() != "Font" { + return false + } + + retValue = true + + } + + return retValue + } + + _, err = validateArrayEntry(xRefTable, d, dictName, "FontFauxing", OPTIONAL, pdf.V10, validateFontDictArray) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, d, dictName, "F", REQUIRED, pdf.V11, nil) + + return err +} + +func validateAnnotationDictWatermark(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.22 + + // FixedPrint, optional, dict + + validateFixedPrintDict := func(d pdf.Dict) bool { + + dictName := "fixedPrintDict" + + // Type, required, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", REQUIRED, pdf.V10, func(s string) bool { return s == "FixedPrint" }) + if err != nil { + return false + } + + // Matrix, optional, integer array, length = 6 + _, err = validateIntegerArrayEntry(xRefTable, d, dictName, "Matrix", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 6 }) + if err != nil { + return false + } + + // H, optional, number + _, err = validateNumberEntry(xRefTable, d, dictName, "H", OPTIONAL, pdf.V10, nil) + if err != nil { + return false + } + + // V, optional, number + _, err = validateNumberEntry(xRefTable, d, dictName, "V", OPTIONAL, pdf.V10, nil) + if err != nil { + return false + } + + return true + } + + _, err := validateDictEntry(xRefTable, d, dictName, "FixedPrint", OPTIONAL, pdf.V10, validateFixedPrintDict) + + return err +} + +func validateAnnotationDict3D(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 13.6.2 + + // AP with entry N, required + + // 3DD, required, 3D stream or 3D reference dict + err := validateStreamDictOrDictEntry(xRefTable, d, dictName, "3DD", REQUIRED, pdf.V16) + if err != nil { + return err + } + + // 3DV, optional, various + _, err = validateEntry(xRefTable, d, dictName, "3DV", OPTIONAL, pdf.V16) + if err != nil { + return err + } + + // 3DA, optional, activation dict + _, err = validateDictEntry(xRefTable, d, dictName, "3DA", OPTIONAL, pdf.V16, nil) + if err != nil { + return err + } + + // 3DI, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "3DI", OPTIONAL, pdf.V16, nil) + + return err +} + +func validateEntryIC(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool, sinceVersion pdf.Version) error { + + // IC, optional, number array, length:3 [0.0 .. 1.0] + validateICArray := func(a pdf.Array) bool { + + if len(a) != 3 { + return false + } + + for _, v := range a { + + o, err := xRefTable.Dereference(v) + if err != nil { + return false + } + + switch o := o.(type) { + case pdf.Integer: + if o < 0 || o > 1 { + return false + } + + case pdf.Float: + if o < 0.0 || o > 1.0 { + return false + } + } + } + + return true + } + + _, err := validateNumberArrayEntry(xRefTable, d, dictName, "IC", required, sinceVersion, validateICArray) + + return err +} + +func validateAnnotationDictRedact(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // see 12.5.6.23 + + // QuadPoints, optional, number array + _, err := validateNumberArrayEntry(xRefTable, d, dictName, "QuadPoints", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // IC, optional, number array, length:3 [0.0 .. 1.0] + err = validateEntryIC(xRefTable, d, dictName, OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // RO, optional, stream + _, err = validateStreamDictEntry(xRefTable, d, dictName, "RO", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // OverlayText, optional, text string + _, err = validateStringEntry(xRefTable, d, dictName, "OverlayText", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Repeat, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "Repeat", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // DA, required, byte string + _, err = validateStringEntry(xRefTable, d, dictName, "DA", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // Q, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "Q", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateRichMediaAnnotation(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + // TODO See extension level 3. + return nil +} + +func validateExDataDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "ExData" + + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "ExData" }) + if err != nil { + return err + } + + _, err = validateNameEntry(xRefTable, d, dictName, "Subtype", REQUIRED, pdf.V10, func(s string) bool { return s == "Markup3D" }) + + return err +} + +func validatePopupEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + + _, err = validateNameEntry(xRefTable, d1, dictName, "Subtype", REQUIRED, pdf.V10, func(s string) bool { return s == "Popup" }) + if err != nil { + return err + } + + _, err = validateAnnotationDict(xRefTable, d1) + if err != nil { + return err + } + + } + + return nil +} + +func validateIRTEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + _, err = validateAnnotationDict(xRefTable, d1) + if err != nil { + return err + } + } + + return nil +} + +func validateMarkupAnnotation(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "markupAnnot" + + // T, optional, text string, since V1.1 + _, err := validateStringEntry(xRefTable, d, dictName, "T", OPTIONAL, pdf.V11, nil) + if err != nil { + return err + } + + // Popup, optional, dict, since V1.3 + err = validatePopupEntry(xRefTable, d, dictName, "Popup", OPTIONAL, pdf.V13) + if err != nil { + return err + } + + // CA, optional, number, since V1.4 + _, err = validateNumberEntry(xRefTable, d, dictName, "CA", OPTIONAL, pdf.V14, nil) + if err != nil { + return err + } + + // RC, optional, text string or stream, since V1.5 + err = validateStringOrStreamEntry(xRefTable, d, dictName, "RC", OPTIONAL, pdf.V15) + if err != nil { + return err + } + + // CreationDate, optional, date, since V1.5 + _, err = validateDateEntry(xRefTable, d, dictName, "CreationDate", OPTIONAL, pdf.V15) + if err != nil { + return err + } + + // IRT, optional, (in reply to) dict, since V1.5 + err = validateIRTEntry(xRefTable, d, dictName, "IRT", OPTIONAL, pdf.V15) + if err != nil { + return err + } + + // Subj, optional, text string, since V1.5 + sinceVersion := pdf.V15 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V14 + } + _, err = validateStringEntry(xRefTable, d, dictName, "Subj", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // RT, optional, name, since V1.6 + validate := func(s string) bool { return s == "R" || s == "Group" } + _, err = validateNameEntry(xRefTable, d, dictName, "RT", OPTIONAL, pdf.V16, validate) + if err != nil { + return err + } + + // IT, optional, name, since V1.6 + _, err = validateNameEntry(xRefTable, d, dictName, "IT", OPTIONAL, pdf.V16, nil) + if err != nil { + return err + } + + // ExData, optional, dict, since V1.7 + d1, err := validateDictEntry(xRefTable, d, dictName, "ExData", OPTIONAL, pdf.V17, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateExDataDict(xRefTable, d1) + if err != nil { + return err + } + } + + return nil +} + +func validateEntryP(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool, sinceVersion pdf.Version) error { + + ir, err := validateIndRefEntry(xRefTable, d, dictName, "P", required, sinceVersion) + if err != nil || ir == nil { + return err + } + + // check if this indRef points to a pageDict. + + d1, err := xRefTable.DereferenceDict(*ir) + if err != nil { + return err + } + + if d1 == nil { + return errors.Errorf("validateEntryP: entry \"P\" (obj#%d) is nil", ir.ObjectNumber) + } + + _, err = validateNameEntry(xRefTable, d1, "pageDict", "Type", REQUIRED, pdf.V10, func(s string) bool { return s == "Page" }) + + return err +} + +func validateAppearDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, "AP", required, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateAppearanceDict(xRefTable, d1) + } + + return err +} + +func validateBorderArrayLength(a pdf.Array) bool { + return len(a) == 0 || len(a) == 3 || len(a) == 4 +} + +func validateAnnotationDictGeneral(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) (*pdf.Name, error) { + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "Annot" }) + if err != nil { + return nil, err + } + + // Subtype, required, name + subtype, err := validateNameEntry(xRefTable, d, dictName, "Subtype", REQUIRED, pdf.V10, nil) + if err != nil { + return nil, err + } + + // Rect, required, rectangle + _, err = validateRectangleEntry(xRefTable, d, dictName, "Rect", REQUIRED, pdf.V10, nil) + if err != nil { + return nil, err + } + + // Contents, optional, text string + _, err = validateStringEntry(xRefTable, d, dictName, "Contents", OPTIONAL, pdf.V10, nil) + if err != nil { + return nil, err + } + + // P, optional, indRef of page dict + err = validateEntryP(xRefTable, d, dictName, OPTIONAL, pdf.V10) + if err != nil { + return nil, err + } + + // NM, optional, text string, since V1.4 + _, err = validateStringEntry(xRefTable, d, dictName, "NM", OPTIONAL, pdf.V14, nil) + if err != nil { + return nil, err + } + + // M, optional, date string in any format, since V1.1 + _, err = validateStringEntry(xRefTable, d, dictName, "M", OPTIONAL, pdf.V11, nil) + if err != nil { + return nil, err + } + + // F, optional integer, since V1.1, annotation flags + _, err = validateIntegerEntry(xRefTable, d, dictName, "F", OPTIONAL, pdf.V11, nil) + if err != nil { + return nil, err + } + + // AP, optional, appearance dict, since V1.2 + err = validateAppearDictEntry(xRefTable, d, dictName, OPTIONAL, pdf.V12) + if err != nil { + return nil, err + } + + // AS, optional, name, since V1.2 + _, err = validateNameEntry(xRefTable, d, dictName, "AS", OPTIONAL, pdf.V11, nil) + if err != nil { + return nil, err + } + + // Border, optional, array of numbers + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Border", OPTIONAL, pdf.V10, validateBorderArrayLength) + if err != nil { + return nil, err + } + + // C, optional array, of numbers, since V1.1 + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "C", OPTIONAL, pdf.V11, nil) + if err != nil { + return nil, err + } + + // StructParent, optional, integer, since V1.3 + _, err = validateIntegerEntry(xRefTable, d, dictName, "StructParent", OPTIONAL, pdf.V13, nil) + if err != nil { + return nil, err + } + + return subtype, nil +} + +func validateAnnotationDictConcrete(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, subtype pdf.Name) error { + + // OC, optional, content group dict or content membership dict, since V1.5 + // Specifying the optional content properties for the annotation. + sinceVersion := pdf.V15 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + if err := validateOptionalContent(xRefTable, d, dictName, "OC", OPTIONAL, sinceVersion); err != nil { + return err + } + + // see table 169 + + for k, v := range map[string]struct { + validate func(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error + sinceVersion pdf.Version + markup bool + }{ + "Text": {validateAnnotationDictText, pdf.V10, true}, + "Link": {validateAnnotationDictLink, pdf.V10, false}, + "FreeText": {validateAnnotationDictFreeText, pdf.V13, true}, + "Line": {validateAnnotationDictLine, pdf.V13, true}, + "Polygon": {validateAnnotationDictPolyLine, pdf.V15, true}, + "PolyLine": {validateAnnotationDictPolyLine, pdf.V15, true}, + "Highlight": {validateTextMarkupAnnotation, pdf.V13, true}, + "Underline": {validateTextMarkupAnnotation, pdf.V13, true}, + "Squiggly": {validateTextMarkupAnnotation, pdf.V14, true}, + "StrikeOut": {validateTextMarkupAnnotation, pdf.V13, true}, + "Square": {validateAnnotationDictCircleOrSquare, pdf.V13, true}, + "Circle": {validateAnnotationDictCircleOrSquare, pdf.V13, true}, + "Stamp": {validateAnnotationDictStamp, pdf.V13, true}, + "Caret": {validateAnnotationDictCaret, pdf.V15, true}, + "Ink": {validateAnnotationDictInk, pdf.V13, true}, + "Popup": {validateAnnotationDictPopup, pdf.V13, false}, + "FileAttachment": {validateAnnotationDictFileAttachment, pdf.V13, true}, + "Sound": {validateAnnotationDictSound, pdf.V12, true}, + "Movie": {validateAnnotationDictMovie, pdf.V12, false}, + "Widget": {validateAnnotationDictWidget, pdf.V12, false}, + "Screen": {validateAnnotationDictScreen, pdf.V15, false}, + "PrinterMark": {validateAnnotationDictPrinterMark, pdf.V14, false}, + "TrapNet": {validateAnnotationDictTrapNet, pdf.V13, false}, + "Watermark": {validateAnnotationDictWatermark, pdf.V16, false}, + "3D": {validateAnnotationDict3D, pdf.V16, false}, + "Redact": {validateAnnotationDictRedact, pdf.V17, true}, + "RichMedia": {validateRichMediaAnnotation, pdf.V17, false}, + } { + if subtype.Value() == k { + + err := xRefTable.ValidateVersion(k, v.sinceVersion) + if err != nil { + return err + } + + if v.markup { + err := validateMarkupAnnotation(xRefTable, d) + if err != nil { + return err + } + } + + return v.validate(xRefTable, d, k) + } + } + + return errors.Errorf("validateAnnotationDictConcrete: unsupported annotation subtype:%s\n", subtype) +} + +func validateAnnotationDictSpecial(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // AAPL:AKExtras + // No documentation for this PDF-Extension - this is a speculative implementation. + return validateAAPLAKExtrasDictEntry(xRefTable, d, dictName, "AAPL:AKExtras", OPTIONAL, pdf.V10) +} + +func validateAnnotationDict(xRefTable *pdf.XRefTable, d pdf.Dict) (isTrapNet bool, err error) { + + dictName := "annotDict" + + subtype, err := validateAnnotationDictGeneral(xRefTable, d, dictName) + if err != nil { + return false, err + } + + err = validateAnnotationDictConcrete(xRefTable, d, dictName, *subtype) + if err != nil { + return false, err + } + + err = validateAnnotationDictSpecial(xRefTable, d, dictName) + if err != nil { + return false, err + } + + return *subtype == "TrapNet", nil +} + +func validatePageAnnotations(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + a, err := validateArrayEntry(xRefTable, d, "pageDict", "Annots", OPTIONAL, pdf.V10, nil) + if err != nil || a == nil { + return err + } + + // array of indrefs to annotation dicts. + var annotsDict pdf.Dict + + // an optional TrapNetAnnotation has to be the final entry in this list. + hasTrapNet := false + + for _, v := range a { + + if hasTrapNet { + return errors.New("pdfcpu: validatePageAnnotations: corrupted page annotation list, \"TrapNet\" has to be the last entry") + } + + if ir, ok := v.(pdf.IndirectRef); ok { + + log.Validate.Printf("processing annotDict %d\n", ir.ObjectNumber) + + annotsDict, err = xRefTable.DereferenceDict(ir) + if err != nil || annotsDict == nil { + return errors.New("pdfcpu: validatePageAnnotations: corrupted annotation dict") + } + + } else if annotsDict, ok = v.(pdf.Dict); !ok { + return errors.New("pdfcpu: validatePageAnnotations: corrupted array of indrefs") + } + + hasTrapNet, err = validateAnnotationDict(xRefTable, annotsDict) + if err != nil { + return err + } + + } + + return nil +} + +func validatePagesAnnotations(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // Get number of pages of this PDF file. + pageCount := d.IntEntry("Count") + if pageCount == nil { + return errors.New("pdfcpu: validatePagesAnnotations: missing \"Count\"") + } + + log.Validate.Printf("validatePagesAnnotations: This page node has %d pages\n", *pageCount) + + // Iterate over page tree. + kidsArray := d.ArrayEntry("Kids") + + for _, v := range kidsArray { + + if v == nil { + log.Validate.Println("validatePagesAnnotations: kid is nil") + continue + } + + d, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + if d == nil { + return errors.New("pdfcpu: validatePagesAnnotations: pageNodeDict is null") + } + + dictType := d.Type() + if dictType == nil { + return errors.New("pdfcpu: validatePagesAnnotations: missing pageNodeDict type") + } + + switch *dictType { + + case "Pages": + // Recurse over pagetree + err = validatePagesAnnotations(xRefTable, d) + if err != nil { + return err + } + + case "Page": + err = validatePageAnnotations(xRefTable, d) + if err != nil { + return err + } + + default: + return errors.Errorf("validatePagesAnnotations: expected dict type: %s\n", *dictType) + + } + + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/colorspace.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/colorspace.go new file mode 100644 index 0000000..f504198 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/colorspace.go @@ -0,0 +1,641 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateDeviceColorSpaceName(s string) bool { + return pdf.MemberOf(s, []string{pdf.DeviceGrayCS, pdf.DeviceRGBCS, pdf.DeviceCMYKCS}) +} + +func validateCalGrayColorSpace(xRefTable *pdf.XRefTable, a pdf.Array, sinceVersion pdf.Version) error { + + dictName := "calGrayCSDict" + + // Version check + err := xRefTable.ValidateVersion(dictName, sinceVersion) + if err != nil { + return err + } + + if len(a) != 2 { + return errors.Errorf("validateCalGrayColorSpace: invalid array length %d (expected 2) \n.", len(a)) + } + + d, err := xRefTable.DereferenceDict(a[1]) + if err != nil || d == nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "WhitePoint", REQUIRED, sinceVersion, func(a pdf.Array) bool { return len(a) == 3 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "BlackPoint", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 3 }) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, d, dictName, "Gamma", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateCalRGBColorSpace(xRefTable *pdf.XRefTable, a pdf.Array, sinceVersion pdf.Version) error { + + dictName := "calRGBCSDict" + + err := xRefTable.ValidateVersion(dictName, sinceVersion) + if err != nil { + return err + } + + if len(a) != 2 { + return errors.Errorf("validateCalRGBColorSpace: invalid array length %d (expected 2) \n.", len(a)) + } + + d, err := xRefTable.DereferenceDict(a[1]) + if err != nil || d == nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "WhitePoint", REQUIRED, sinceVersion, func(a pdf.Array) bool { return len(a) == 3 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "BlackPoint", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 3 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Gamma", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 3 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Matrix", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 9 }) + + return err +} + +func validateLabColorSpace(xRefTable *pdf.XRefTable, a pdf.Array, sinceVersion pdf.Version) error { + + dictName := "labCSDict" + + err := xRefTable.ValidateVersion(dictName, sinceVersion) + if err != nil { + return err + } + + if len(a) != 2 { + return errors.Errorf("validateLabColorSpace: invalid array length %d (expected 2) \n.", len(a)) + } + + d, err := xRefTable.DereferenceDict(a[1]) + if err != nil || d == nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "WhitePoint", REQUIRED, sinceVersion, func(a pdf.Array) bool { return len(a) == 3 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "BlackPoint", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 3 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Range", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 4 }) + + return err +} + +func validateICCBasedColorSpace(xRefTable *pdf.XRefTable, a pdf.Array, sinceVersion pdf.Version) error { + + // see 8.6.5.5 + + dictName := "ICCBasedColorSpace" + + err := xRefTable.ValidateVersion(dictName, sinceVersion) + if err != nil { + return err + } + + if len(a) != 2 { + return errors.Errorf("validateICCBasedColorSpace: invalid array length %d (expected 2) \n.", len(a)) + } + + sd, err := validateStreamDict(xRefTable, a[1]) + if err != nil || sd == nil { + return err + } + + validate := func(i int) bool { return pdf.IntMemberOf(i, []int{1, 3, 4}) } + N, err := validateIntegerEntry(xRefTable, sd.Dict, dictName, "N", REQUIRED, sinceVersion, validate) + if err != nil { + return err + } + + err = validateColorSpaceEntry(xRefTable, sd.Dict, dictName, "Alternate", OPTIONAL, ExcludePatternCS) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, sd.Dict, dictName, "Range", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 2*N.Value() }) + if err != nil { + return err + } + + // Metadata, stream, optional since V1.4 + return validateMetadata(xRefTable, sd.Dict, OPTIONAL, pdf.V14) +} + +func validateIndexedColorSpaceLookuptable(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o.(type) { + + case pdf.StringLiteral, pdf.HexLiteral: + err = xRefTable.ValidateVersion("IndexedColorSpaceLookuptable", pdf.V12) + + case pdf.StreamDict: + err = xRefTable.ValidateVersion("IndexedColorSpaceLookuptable", sinceVersion) + + default: + err = errors.Errorf("validateIndexedColorSpaceLookuptable: invalid type\n") + + } + + return err +} + +func validateIndexedColorSpace(xRefTable *pdf.XRefTable, a pdf.Array, sinceVersion pdf.Version) error { + + // see 8.6.6.3 + + err := xRefTable.ValidateVersion("IndexedColorSpace", sinceVersion) + if err != nil { + return err + } + + if len(a) != 4 { + return errors.Errorf("validateIndexedColorSpace: invalid array length %d (expected 4) \n.", len(a)) + } + + // arr[1] base: base colorspace + err = validateColorSpace(xRefTable, a[1], ExcludePatternCS) + if err != nil { + return err + } + + // arr[2] hival: 0 <= int <= 255 + _, err = validateInteger(xRefTable, a[2], func(i int) bool { return i >= 0 && i <= 255 }) + if err != nil { + return err + } + + // arr[3] lookup: stream since V1.2 or byte string + return validateIndexedColorSpaceLookuptable(xRefTable, a[3], sinceVersion) +} + +func validatePatternColorSpace(xRefTable *pdf.XRefTable, a pdf.Array, sinceVersion pdf.Version) error { + + err := xRefTable.ValidateVersion("PatternColorSpace", sinceVersion) + if err != nil { + return err + } + + if len(a) < 1 || len(a) > 2 { + return errors.Errorf("validatePatternColorSpace: invalid array length %d (expected 1 or 2) \n.", len(a)) + } + + // 8.7.3.3: arr[1]: name of underlying color space, any cs except PatternCS + if len(a) == 2 { + err := validateColorSpace(xRefTable, a[1], ExcludePatternCS) + if err != nil { + return err + } + } + + return nil +} + +func validateSeparationColorSpace(xRefTable *pdf.XRefTable, a pdf.Array, sinceVersion pdf.Version) error { + + // see 8.6.6.4 + + err := xRefTable.ValidateVersion("SeparationColorSpace", sinceVersion) + if err != nil { + return err + } + + if len(a) != 4 { + return errors.Errorf("validateSeparationColorSpace: invalid array length %d (expected 4) \n.", len(a)) + } + + // arr[1]: colorant name, arbitrary + _, err = validateName(xRefTable, a[1], nil) + if err != nil { + return err + } + + // arr[2]: alternate space + err = validateColorSpace(xRefTable, a[2], ExcludePatternCS) + if err != nil { + return err + } + + // arr[3]: tintTransform, function + return validateFunction(xRefTable, a[3]) +} + +func validateDeviceNColorSpaceColorantsDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + for _, obj := range d { + + a, err := xRefTable.DereferenceArray(obj) + if err != nil { + return err + } + + if a != nil { + err = validateSeparationColorSpace(xRefTable, a, pdf.V12) + if err != nil { + return err + } + } + + } + + return nil +} + +func validateDeviceNColorSpaceProcessDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "DeviceNCSProcessDict" + + err := validateColorSpaceEntry(xRefTable, d, dictName, "ColorSpace", REQUIRED, true) + if err != nil { + return err + } + + _, err = validateNameArrayEntry(xRefTable, d, dictName, "Components", REQUIRED, pdf.V10, nil) + + return err +} + +func validateDeviceNColorSpaceSoliditiesDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + for _, obj := range d { + _, err := validateFloat(xRefTable, obj, func(f float64) bool { return f >= 0.0 && f <= 1.0 }) + if err != nil { + return err + } + } + + return nil +} + +func validateDeviceNColorSpaceDotGainDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + for _, obj := range d { + err := validateFunction(xRefTable, obj) + if err != nil { + return err + } + } + + return nil +} + +func validateDeviceNColorSpaceMixingHintsDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "deviceNCSMixingHintsDict" + + d1, err := validateDictEntry(xRefTable, d, dictName, "Solidities", OPTIONAL, pdf.V11, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateDeviceNColorSpaceSoliditiesDict(xRefTable, d1) + if err != nil { + return err + } + } + + _, err = validateNameArrayEntry(xRefTable, d, dictName, "PrintingOrder", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + d1, err = validateDictEntry(xRefTable, d, dictName, "DotGain", OPTIONAL, pdf.V11, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateDeviceNColorSpaceDotGainDict(xRefTable, d1) + } + + return err +} + +func validateDeviceNColorSpaceAttributesDict(xRefTable *pdf.XRefTable, o pdf.Object) error { + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + dictName := "deviceNCSAttributesDict" + + sinceVersion := pdf.V16 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + + _, err = validateNameEntry(xRefTable, d, dictName, "Subtype", OPTIONAL, sinceVersion, func(s string) bool { return s == "DeviceN" || s == "NChannel" }) + if err != nil { + return err + } + + d1, err := validateDictEntry(xRefTable, d, dictName, "Colorants", OPTIONAL, pdf.V11, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateDeviceNColorSpaceColorantsDict(xRefTable, d1) + if err != nil { + return err + } + } + + d1, err = validateDictEntry(xRefTable, d, dictName, "Process", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateDeviceNColorSpaceProcessDict(xRefTable, d1) + if err != nil { + return err + } + } + + d1, err = validateDictEntry(xRefTable, d, dictName, "MixingHints", OPTIONAL, pdf.V16, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateDeviceNColorSpaceMixingHintsDict(xRefTable, d1) + } + + return err +} + +func validateDeviceNColorSpace(xRefTable *pdf.XRefTable, a pdf.Array, sinceVersion pdf.Version) error { + + // see 8.6.6.5 + + err := xRefTable.ValidateVersion("DeviceNColorSpace", sinceVersion) + if err != nil { + return err + } + + if len(a) < 4 || len(a) > 5 { + return errors.Errorf("writeDeviceNColorSpace: invalid array length %d (expected 4 or 5) \n.", len(a)) + } + + // arr[1]: array of names specifying the individual color components + // length subject to implementation limit. + _, err = validateNameArray(xRefTable, a[1]) + if err != nil { + return err + } + + // arr[2]: alternate space + err = validateColorSpace(xRefTable, a[2], ExcludePatternCS) + if err != nil { + return err + } + + // arr[3]: tintTransform, function + err = validateFunction(xRefTable, a[3]) + if err != nil { + return err + } + + // arr[4]: color space attributes dict, optional + if len(a) == 5 { + err = validateDeviceNColorSpaceAttributesDict(xRefTable, a[4]) + } + + return err +} + +func validateCSArray(xRefTable *pdf.XRefTable, a pdf.Array, csName string) error { + + // see 8.6 Color Spaces + + switch csName { + + // CIE-based + case pdf.CalGrayCS: + return validateCalGrayColorSpace(xRefTable, a, pdf.V11) + + case pdf.CalRGBCS: + return validateCalRGBColorSpace(xRefTable, a, pdf.V11) + + case pdf.LabCS: + return validateLabColorSpace(xRefTable, a, pdf.V11) + + case pdf.ICCBasedCS: + return validateICCBasedColorSpace(xRefTable, a, pdf.V13) + + // Special + case pdf.IndexedCS: + return validateIndexedColorSpace(xRefTable, a, pdf.V11) + + case pdf.PatternCS: + return validatePatternColorSpace(xRefTable, a, pdf.V12) + + case pdf.SeparationCS: + return validateSeparationColorSpace(xRefTable, a, pdf.V12) + + case pdf.DeviceNCS: + return validateDeviceNColorSpace(xRefTable, a, pdf.V13) + + default: + return errors.Errorf("validateColorSpaceArray: undefined color space: %s\n", csName) + } + +} + +func validateColorSpaceArraySubset(xRefTable *pdf.XRefTable, a pdf.Array, cs []string) error { + + csName, ok := a[0].(pdf.Name) + if !ok { + return errors.New("pdfcpu: validateColorSpaceArraySubset: corrupt Colorspace array") + } + + for _, v := range cs { + if csName.Value() == v { + return validateCSArray(xRefTable, a, v) + } + } + + return errors.Errorf("pdfcpu: validateColorSpaceArraySubset: invalid color space: %s\n", csName) +} + +func validateColorSpaceArray(xRefTable *pdf.XRefTable, a pdf.Array, excludePatternCS bool) (err error) { + + // see 8.6 Color Spaces + + name, ok := a[0].(pdf.Name) + if !ok { + return errors.New("pdfcpu: validateColorSpaceArray: corrupt Colorspace array") + } + + switch name { + + // CIE-based + case pdf.CalGrayCS: + err = validateCalGrayColorSpace(xRefTable, a, pdf.V11) + + case pdf.CalRGBCS: + err = validateCalRGBColorSpace(xRefTable, a, pdf.V11) + + case pdf.LabCS: + err = validateLabColorSpace(xRefTable, a, pdf.V11) + + case pdf.ICCBasedCS: + err = validateICCBasedColorSpace(xRefTable, a, pdf.V13) + + // Special + case pdf.IndexedCS: + err = validateIndexedColorSpace(xRefTable, a, pdf.V11) + + case pdf.PatternCS: + if excludePatternCS { + return errors.New("pdfcpu: validateColorSpaceArray: Pattern color space not allowed") + } + err = validatePatternColorSpace(xRefTable, a, pdf.V12) + + case pdf.SeparationCS: + err = validateSeparationColorSpace(xRefTable, a, pdf.V12) + + case pdf.DeviceNCS: + err = validateDeviceNColorSpace(xRefTable, a, pdf.V13) + + default: + err = errors.Errorf("pdfcpu: validateColorSpaceArray: undefined color space: %s\n", name) + } + + return err +} + +func validateColorSpace(xRefTable *pdf.XRefTable, o pdf.Object, excludePatternCS bool) error { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + validateSpecialColorSpaceName := func(s string) bool { return pdf.MemberOf(s, []string{"Pattern"}) } + if ok := validateDeviceColorSpaceName(o.Value()) || validateSpecialColorSpaceName(o.Value()); !ok { + err = errors.Errorf("validateColorSpace: invalid device color space name: %v\n", o) + } + + case pdf.Array: + err = validateColorSpaceArray(xRefTable, o, excludePatternCS) + + default: + err = errors.New("pdfcpu: validateColorSpace: corrupt obj typ, must be Name or Array") + + } + + return err +} + +func validateColorSpaceEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, excludePatternCS bool) error { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, pdf.V10) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + if ok := validateDeviceColorSpaceName(o.Value()); !ok { + err = errors.Errorf("pdfcpu: validateColorSpaceEntry: Name:%s\n", o.Value()) + } + + case pdf.Array: + err = validateColorSpaceArray(xRefTable, o, excludePatternCS) + + default: + err = errors.Errorf("pdfcpu: validateColorSpaceEntry: dict=%s corrupt entry \"%s\"\n", dictName, entryName) + + } + + return err +} + +func validateColorSpaceResourceDict(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // see 8.6 Color Spaces + + // Version check + err := xRefTable.ValidateVersion("ColorSpaceResourceDict", sinceVersion) + if err != nil { + return err + } + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + // Iterate over colorspace resource dictionary + for _, o := range d { + + // Process colorspace + err = validateColorSpace(xRefTable, o, IncludePatternCS) + if err != nil { + return err + } + + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/destination.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/destination.go new file mode 100644 index 0000000..5863cde --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/destination.go @@ -0,0 +1,156 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateDestinationArrayFirstElement(xRefTable *pdf.XRefTable, a pdf.Array) (pdf.Object, error) { + + o, err := xRefTable.Dereference(a[0]) + if err != nil || o == nil { + return nil, err + } + + switch o := o.(type) { + + case pdf.Integer: // no further processing + + case pdf.Dict: + if o.Type() == nil || *o.Type() != "Page" { + err = errors.New("pdfcpu: validateDestinationArrayFirstElement: first element refers to invalid destination page dict") + } + + default: + err = errors.Errorf("pdfcpu: validateDestinationArrayFirstElement: first element must be a pageDict indRef or an integer: %v", o) + } + + return o, err +} + +func validateDestinationArrayLength(a pdf.Array) bool { + l := len(a) + return l == 2 || l == 3 || l == 5 || l == 6 +} + +func validateDestinationArray(xRefTable *pdf.XRefTable, a pdf.Array) error { + + // Validate first element: indRef of page dict or pageNumber(int) of remote doc for remote Go-to Action or nil. + + o, err := validateDestinationArrayFirstElement(xRefTable, a) + if err != nil || o == nil { + return err + } + + if !validateDestinationArrayLength(a) { + return errors.New("pdfcpu: validateDestinationArray: invalid length") + } + + // Validate rest of array elements. + + name, ok := a[1].(pdf.Name) + if !ok { + return errors.New("pdfcpu: validateDestinationArray: second element must be a name") + } + + var nameErr bool + + switch len(a) { + + case 2: + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + nameErr = !pdf.MemberOf(name.Value(), []string{"Fit", "FitB", "FitH"}) + } else { + nameErr = !pdf.MemberOf(name.Value(), []string{"Fit", "FitB"}) + } + + case 3: + nameErr = name.Value() != "FitH" && name.Value() != "FitV" && name.Value() != "FitBH" + + case 5: + nameErr = name.Value() != "XYZ" + + case 6: + nameErr = name.Value() != "FitR" + + default: + return errors.Errorf("validateDestinationArray: array length %d not allowed: %v", len(a), a) + } + + if nameErr { + return errors.New("pdfcpu: validateDestinationArray: arr[1] corrupt") + } + + return nil +} + +func validateDestinationDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // D, required, array + a, err := validateArrayEntry(xRefTable, d, "DestinationDict", "D", REQUIRED, pdf.V10, nil) + if err != nil || a == nil { + return err + } + + return validateDestinationArray(xRefTable, a) +} + +func validateDestination(xRefTable *pdf.XRefTable, o pdf.Object) error { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + // no further processing. + + case pdf.StringLiteral: + // no further processing. + + case pdf.HexLiteral: + // no further processing. + + case pdf.Dict: + err = validateDestinationDict(xRefTable, o) + + case pdf.Array: + err = validateDestinationArray(xRefTable, o) + + default: + err = errors.New("pdfcpu: validateDestination: unsupported PDF object") + + } + + return err +} + +func validateDestinationEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + // see 12.3.2 + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil { + return err + } + + return validateDestination(xRefTable, o) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/extGState.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/extGState.go new file mode 100644 index 0000000..436111a --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/extGState.go @@ -0,0 +1,866 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// see 8.4.5 Graphics State Parameter Dictionaries + +func validateBlendMode(s string) bool { + + // see 11.3.5; table 136 + + return pdf.MemberOf(s, []string{"None", "Normal", "Compatible", "Multiply", "Screen", "Overlay", "Darken", "Lighten", + "ColorDodge", "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion", + "Hue", "Saturation", "Color", "Luminosity"}) +} + +func validateLineDashPatternEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + a, err := validateArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil || a == nil { + return err + } + + _, err = validateIntegerArray(xRefTable, a[0]) + if err != nil { + return err + } + + _, err = validateInteger(xRefTable, a[1], nil) + + return err +} + +func validateBG2Entry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + s := o.Value() + if s != "Default" { + err = errors.New("pdfcpu: validateBG2Entry: corrupt name") + } + + case pdf.Dict: + err = processFunction(xRefTable, o) + + case pdf.StreamDict: + err = processFunction(xRefTable, o) + + default: + err = errors.Errorf("pdfcpu: validateBG2Entry: dict=%s corrupt entry \"%s\"\n", dictName, entryName) + + } + + return err +} + +func validateUCR2Entry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + s := o.Value() + if s != "Default" { + err = errors.New("pdfcpu: writeUCR2Entry: corrupt name") + } + + case pdf.Dict: + err = processFunction(xRefTable, o) + + case pdf.StreamDict: + err = processFunction(xRefTable, o) + + default: + err = errors.Errorf("pdfcpu: validateUCR2Entry: dict=%s corrupt entry \"%s\"\n", dictName, entryName) + + } + + return err +} + +func validateTransferFunction(xRefTable *pdf.XRefTable, o pdf.Object) (err error) { + + switch o := o.(type) { + + case pdf.Name: + s := o.Value() + if s != "Identity" { + return errors.New("pdfcpu: validateTransferFunction: corrupt name") + } + + case pdf.Array: + + if len(o) != 4 { + return errors.New("pdfcpu: validateTransferFunction: corrupt function array") + } + + for _, o := range o { + + o, err := xRefTable.Dereference(o) + if err != nil { + return err + } + if o == nil { + continue + } + + err = processFunction(xRefTable, o) + if err != nil { + return err + } + + } + + case pdf.Dict: + err = processFunction(xRefTable, o) + + case pdf.StreamDict: + err = processFunction(xRefTable, o) + + default: + return errors.Errorf("validateTransferFunction: corrupt entry: %v\n", o) + + } + + return err +} + +func validateTransferFunctionEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + return validateTransferFunction(xRefTable, o) +} + +func validateTR2(xRefTable *pdf.XRefTable, o pdf.Object) (err error) { + + switch o := o.(type) { + + case pdf.Name: + s := o.Value() + if s != "Identity" && s != "Default" { + return errors.Errorf("pdfcpu: validateTR2: corrupt name\n") + } + + case pdf.Array: + + if len(o) != 4 { + return errors.New("pdfcpu: validateTR2: corrupt function array") + } + + for _, o := range o { + + o, err = xRefTable.Dereference(o) + if err != nil { + return + } + + if o == nil { + continue + } + + err = processFunction(xRefTable, o) + if err != nil { + return + } + + } + + case pdf.Dict: + err = processFunction(xRefTable, o) + + case pdf.StreamDict: + err = processFunction(xRefTable, o) + + default: + return errors.Errorf("validateTR2: corrupt entry %v\n", o) + + } + + return err +} + +func validateTR2Entry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + return validateTR2(xRefTable, o) +} + +func validateSpotFunctionEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + validateSpotFunctionName := func(s string) bool { + return pdf.MemberOf(s, []string{ + "SimpleDot", "InvertedSimpleDot", "DoubleDot", "InvertedDoubleDot", "CosineDot", + "Double", "InvertedDouble", "Line", "LineX", "LineY", "Round", "Ellipse", "EllipseA", + "InvertedEllipseA", "EllipseB", "EllipseC", "InvertedEllipseC", "Square", "Cross", "Rhomboid"}) + } + s := o.Value() + if !validateSpotFunctionName(s) { + return errors.Errorf("validateSpotFunctionEntry: corrupt name\n") + } + + case pdf.Dict: + err = processFunction(xRefTable, o) + + case pdf.StreamDict: + err = processFunction(xRefTable, o) + + default: + return errors.Errorf("validateSpotFunctionEntry: dict=%s corrupt entry \"%s\"\n", dictName, entryName) + + } + + return err +} + +func validateType1HalftoneDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "type1HalftoneDict" + + // HalftoneName, optional, string + _, err := validateStringEntry(xRefTable, d, dictName, "HalftoneName", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // Frequency, required, number + _, err = validateNumberEntry(xRefTable, d, dictName, "Frequency", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + // Angle, required, number + _, err = validateNumberEntry(xRefTable, d, dictName, "Angle", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + // SpotFunction, required, function or name + err = validateSpotFunctionEntry(xRefTable, d, dictName, "SpotFunction", REQUIRED, sinceVersion) + if err != nil { + return err + } + + // TransferFunction, optional, function + err = validateTransferFunctionEntry(xRefTable, d, dictName, "TransferFunction", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + _, err = validateBooleanEntry(xRefTable, d, dictName, "AccurateScreens", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateType5HalftoneDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "type5HalftoneDict" + + _, err := validateStringEntry(xRefTable, d, dictName, "HalftoneName", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + for _, c := range []string{"Gray", "Red", "Green", "Blue", "Cyan", "Magenta", "Yellow", "Black"} { + err = validateHalfToneEntry(xRefTable, d, dictName, c, OPTIONAL, sinceVersion) + if err != nil { + return err + } + } + + return validateHalfToneEntry(xRefTable, d, dictName, "Default", REQUIRED, sinceVersion) +} + +func validateType6HalftoneStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict, sinceVersion pdf.Version) error { + + dictName := "type6HalftoneDict" + + _, err := validateStringEntry(xRefTable, sd.Dict, dictName, "HalftoneName", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "Width", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "Height", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + return validateTransferFunctionEntry(xRefTable, sd.Dict, dictName, "TransferFunction", OPTIONAL, sinceVersion) +} + +func validateType10HalftoneStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict, sinceVersion pdf.Version) error { + + dictName := "type10HalftoneDict" + + _, err := validateStringEntry(xRefTable, sd.Dict, dictName, "HalftoneName", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "Xsquare", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "Ysquare", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + return validateTransferFunctionEntry(xRefTable, sd.Dict, dictName, "TransferFunction", OPTIONAL, sinceVersion) +} + +func validateType16HalftoneStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict, sinceVersion pdf.Version) error { + + dictName := "type16HalftoneDict" + + _, err := validateStringEntry(xRefTable, sd.Dict, dictName, "HalftoneName", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "Width", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "Height", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "Width2", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "Height2", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + return validateTransferFunctionEntry(xRefTable, sd.Dict, dictName, "TransferFunction", OPTIONAL, sinceVersion) +} + +func validateHalfToneDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "halfToneDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Halftone" }) + if err != nil { + return err + } + + // HalftoneType, required, integer + halftoneType, err := validateIntegerEntry(xRefTable, d, dictName, "HalftoneType", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + switch *halftoneType { + + case 1: + err = validateType1HalftoneDict(xRefTable, d, sinceVersion) + + case 5: + err = validateType5HalftoneDict(xRefTable, d, sinceVersion) + + default: + err = errors.Errorf("validateHalfToneDict: unknown halftoneTyp: %d\n", *halftoneType) + + } + + return err +} + +func validateHalfToneStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict, sinceVersion pdf.Version) error { + + dictName := "writeHalfToneStreamDict" + + // Type, name, optional + _, err := validateNameEntry(xRefTable, sd.Dict, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Halftone" }) + if err != nil { + return err + } + + // HalftoneType, required, integer + halftoneType, err := validateIntegerEntry(xRefTable, sd.Dict, dictName, "HalftoneType", REQUIRED, sinceVersion, nil) + if err != nil || halftoneType == nil { + return err + } + + switch *halftoneType { + + case 6: + err = validateType6HalftoneStreamDict(xRefTable, sd, sinceVersion) + + case 10: + err = validateType10HalftoneStreamDict(xRefTable, sd, sinceVersion) + + case 16: + err = validateType16HalftoneStreamDict(xRefTable, sd, sinceVersion) + + default: + err = errors.Errorf("validateHalfToneStreamDict: unknown halftoneTyp: %d\n", *halftoneType) + + } + + return err +} + +func validateHalfToneEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) (err error) { + + // See 10.5 + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + if o.Value() != "Default" { + return errors.Errorf("pdfcpu: validateHalfToneEntry: undefined name: %s\n", o) + } + + case pdf.Dict: + err = validateHalfToneDict(xRefTable, o, sinceVersion) + + case pdf.StreamDict: + err = validateHalfToneStreamDict(xRefTable, &o, sinceVersion) + + default: + err = errors.New("pdfcpu: validateHalfToneEntry: corrupt (stream)dict") + } + + return err +} + +func validateBlendModeEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + _, err = xRefTable.DereferenceName(o, sinceVersion, validateBlendMode) + if err != nil { + return err + } + + case pdf.Array: + for _, o := range o { + _, err = xRefTable.DereferenceName(o, sinceVersion, validateBlendMode) + if err != nil { + return err + } + } + + default: + return errors.Errorf("validateBlendModeEntry: dict=%s corrupt entry \"%s\"\n", dictName, entryName) + + } + + return nil +} + +func validateSoftMaskTransferFunctionEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + s := o.Value() + if s != "Identity" { + return errors.New("pdfcpu: validateSoftMaskTransferFunctionEntry: corrupt name") + } + + case pdf.Dict: + err = processFunction(xRefTable, o) + + case pdf.StreamDict: + err = processFunction(xRefTable, o) + + default: + return errors.Errorf("pdfcpu: validateSoftMaskTransferFunctionEntry: dict=%s corrupt entry \"%s\"\n", dictName, entryName) + + } + + return err +} + +func validateSoftMaskDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // see 11.6.5.2 + + dictName := "softMaskDict" + + // Type, name, optional + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "Mask" }) + if err != nil { + return err + } + + // S, name, required + _, err = validateNameEntry(xRefTable, d, dictName, "S", REQUIRED, pdf.V10, func(s string) bool { return s == "Alpha" || s == "Luminosity" }) + if err != nil { + return err + } + + // G, stream, required + // A transparency group XObject (see “Transparency Group XObjects”) + // to be used as the source of alpha or colour values for deriving the mask. + sd, err := validateStreamDictEntry(xRefTable, d, dictName, "G", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + if sd != nil { + err = validateXObjectStreamDict(xRefTable, *sd) + if err != nil { + return err + } + } + + // TR (Optional) function or name + // A function object (see “Functions”) specifying the transfer function + // to be used in deriving the mask values. + err = validateSoftMaskTransferFunctionEntry(xRefTable, d, dictName, "TR", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // BC, number array, optional + // Array of component values specifying the colour to be used + // as the backdrop against which to composite the transparency group XObject G. + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "BC", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateSoftMaskEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + // see 11.3.7.2 Source Shape and Opacity + // see 11.6.4.3 Mask Shape and Opacity + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + s := o.Value() + if !validateBlendMode(s) { + return errors.Errorf("pdfcpu: validateSoftMaskEntry: invalid soft mask: %s\n", s) + } + + case pdf.Dict: + err = validateSoftMaskDict(xRefTable, o) + + default: + err = errors.Errorf("pdfcpu: validateSoftMaskEntry: dict=%s corrupt entry \"%s\"\n", dictName, entryName) + + } + + return err +} + +func validateExtGStateDictPart1(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // LW, number, optional, since V1.3 + _, err := validateNumberEntry(xRefTable, d, dictName, "LW", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // LC, integer, optional, since V1.3 + _, err = validateIntegerEntry(xRefTable, d, dictName, "LC", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // LJ, integer, optional, since V1.3 + _, err = validateIntegerEntry(xRefTable, d, dictName, "LJ", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // ML, number, optional, since V1.3 + _, err = validateNumberEntry(xRefTable, d, dictName, "ML", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // D, array, optional, since V1.3, [dashArray dashPhase(integer)] + err = validateLineDashPatternEntry(xRefTable, d, dictName, "D", OPTIONAL, pdf.V13) + if err != nil { + return err + } + + // RI, name, optional, since V1.3 + _, err = validateNameEntry(xRefTable, d, dictName, "RI", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // OP, boolean, optional, + _, err = validateBooleanEntry(xRefTable, d, dictName, "OP", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // op, boolean, optional, since V1.3 + _, err = validateBooleanEntry(xRefTable, d, dictName, "op", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // OPM, integer, optional, since V1.3 + _, err = validateIntegerEntry(xRefTable, d, dictName, "OPM", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // Font, array, optional, since V1.3 + _, err = validateArrayEntry(xRefTable, d, dictName, "Font", OPTIONAL, pdf.V13, nil) + + return err +} + +func validateExtGStateDictPart2(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // BG, function, optional, black-generation function, see 10.3.4 + err := validateFunctionEntry(xRefTable, d, dictName, "BG", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // BG2, function or name(/Default), optional, since V1.3 + err = validateBG2Entry(xRefTable, d, dictName, "BG2", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // UCR, function, optional, undercolor-removal function, see 10.3.4 + err = validateFunctionEntry(xRefTable, d, dictName, "UCR", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // UCR2, function or name(/Default), optional, since V1.3 + err = validateUCR2Entry(xRefTable, d, dictName, "UCR2", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // TR, function, array of 4 functions or name(/Identity), optional, see 10.4 transfer functions + err = validateTransferFunctionEntry(xRefTable, d, dictName, "TR", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // TR2, function, array of 4 functions or name(/Identity,/Default), optional, since V1.3 + err = validateTR2Entry(xRefTable, d, dictName, "TR2", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // HT, dict, stream or name, optional + // half tone dictionary or stream or /Default, see 10.5 + err = validateHalfToneEntry(xRefTable, d, dictName, "HT", OPTIONAL, pdf.V12) + if err != nil { + return err + } + + // FL, number, optional, since V1.3, flatness tolerance, see 10.6.2 + _, err = validateNumberEntry(xRefTable, d, dictName, "FL", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // SM, number, optional, since V1.3, smoothness tolerance + _, err = validateNumberEntry(xRefTable, d, dictName, "SM", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // SA, boolean, optional, see 10.6.5 Automatic Stroke Adjustment + _, err = validateBooleanEntry(xRefTable, d, dictName, "SA", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateExtGStateDictPart3(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // BM, name or array, optional, since V1.4 + sinceVersion := pdf.V14 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + err := validateBlendModeEntry(xRefTable, d, dictName, "BM", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // SMask, dict or name, optional, since V1.4 + sinceVersion = pdf.V14 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + err = validateSoftMaskEntry(xRefTable, d, dictName, "SMask", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // CA, number, optional, since V1.4, current stroking alpha constant, see 11.3.7.2 and 11.6.4.4 + sinceVersion = pdf.V14 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + _, err = validateNumberEntry(xRefTable, d, dictName, "CA", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // ca, number, optional, since V1.4, same as CA but for nonstroking operations. + sinceVersion = pdf.V14 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + _, err = validateNumberEntry(xRefTable, d, dictName, "ca", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // AIS, alpha source flag "alpha is shape", boolean, optional, since V1.4 + sinceVersion = pdf.V14 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + _, err = validateBooleanEntry(xRefTable, d, dictName, "AIS", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // TK, boolean, optional, since V1.4, text knockout flag. + _, err = validateBooleanEntry(xRefTable, d, dictName, "TK", OPTIONAL, pdf.V14, nil) + + return err +} + +func validateExtGStateDict(xRefTable *pdf.XRefTable, o pdf.Object) error { + + // 8.4.5 Graphics State Parameter Dictionaries + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + dictName := "extGStateDict" + + // Type, name, optional + _, err = validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "ExtGState" }) + if err != nil { + return err + } + + err = validateExtGStateDictPart1(xRefTable, d, dictName) + if err != nil { + return err + } + + err = validateExtGStateDictPart2(xRefTable, d, dictName) + if err != nil { + return err + } + + return validateExtGStateDictPart3(xRefTable, d, dictName) +} + +func validateExtGStateResourceDict(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + // Version check + err = xRefTable.ValidateVersion("ExtGStateResourceDict", sinceVersion) + if err != nil { + return err + } + + // Iterate over extGState resource dictionary + for _, o := range d { + + // Process extGStateDict + err = validateExtGStateDict(xRefTable, o) + if err != nil { + return err + } + + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/fileSpec.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/fileSpec.go new file mode 100644 index 0000000..043e99f --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/fileSpec.go @@ -0,0 +1,501 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + "net/url" + + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// See 7.11.4 + +func validateFileSpecString(s string) bool { + + // see 7.11.2 + // The standard format for representing a simple file specification in string form divides the string into component substrings + // separated by the SOLIDUS character (2Fh) (/). The SOLIDUS is a generic component separator that shall be mapped to the appropriate + // platform-specific separator when generating a platform-dependent file name. Any of the components may be empty. + // If a component contains one or more literal SOLIDI, each shall be preceded by a REVERSE SOLIDUS (5Ch) (\), which in turn shall be + // preceded by another REVERSE SOLIDUS to indicate that it is part of the string and not an escape character. + // + // EXAMPLE ( in\\/out ) + // represents the file name in/out + + // I have not seen an instance of a single file spec string that actually complies with this definition and uses + // the double reverse solidi in front of the solidus, because of that we simply + return true +} + +func validateURLString(s string) bool { + + // RFC1738 compliant URL, see 7.11.5 + + _, err := url.ParseRequestURI(s) + + return err == nil +} + +func validateEmbeddedFileStreamMacParameterDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "embeddedFileStreamMacParameterDict" + + // Subtype, optional integer + // The embedded file's file type integer encoded according to Mac OS conventions. + _, err := validateIntegerEntry(xRefTable, d, dictName, "Subtype", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Creator, optional integer + // The embedded file's creator signature integer encoded according to Mac OS conventions. + _, err = validateIntegerEntry(xRefTable, d, dictName, "Creator", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // ResFork, optional stream dict + // The binary contents of the embedded file's resource fork. + _, err = validateStreamDictEntry(xRefTable, d, dictName, "ResFork", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateEmbeddedFileStreamParameterDict(xRefTable *pdf.XRefTable, o pdf.Object) error { + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + dictName := "embeddedFileStreamParmDict" + + // Size, optional integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "Size", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // CreationDate, optional date + _, err = validateDateEntry(xRefTable, d, dictName, "CreationDate", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // ModDate, optional date + _, err = validateDateEntry(xRefTable, d, dictName, "ModDate", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // Mac, optional dict + macDict, err := validateDictEntry(xRefTable, d, dictName, "Mac", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + if macDict != nil { + err = validateEmbeddedFileStreamMacParameterDict(xRefTable, macDict) + if err != nil { + return err + } + } + + // CheckSum, optional string + _, err = validateStringEntry(xRefTable, d, dictName, "CheckSum", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateEmbeddedFileStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict) error { + + dictName := "embeddedFileStreamDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, sd.Dict, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "EmbeddedFile" }) + if err != nil { + return err + } + + // Subtype, optional, name + _, err = validateNameEntry(xRefTable, sd.Dict, dictName, "Subtype", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Params, optional, dict + // parameter dict containing additional file-specific information. + if o, found := sd.Dict.Find("Params"); found && o != nil { + err = validateEmbeddedFileStreamParameterDict(xRefTable, o) + } + + return err +} + +func validateFileSpecDictEntriesEFAndRFKeys(k string) bool { + return k == "F" || k == "UF" || k == "DOS" || k == "Mac" || k == "Unix" +} + +func validateFileSpecDictEntryEFDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + for k, obj := range d { + + if !validateFileSpecDictEntriesEFAndRFKeys(k) { + return errors.Errorf("validateFileSpecEntriesEFAndRF: invalid key: %s", k) + } + + // value must be embedded file stream dict + // see 7.11.4 + sd, err := validateStreamDict(xRefTable, obj) + if err != nil { + return err + } + if sd == nil { + continue + } + + err = validateEmbeddedFileStreamDict(xRefTable, sd) + if err != nil { + return err + } + + } + + return nil +} + +func validateRFDictFilesArray(xRefTable *pdf.XRefTable, a pdf.Array) error { + + if len(a)%2 > 0 { + return errors.New("pdfcpu: validateRFDictFilesArray: rfDict array corrupt") + } + + for k, v := range a { + + if v == nil { + return errors.New("pdfcpu: validateRFDictFilesArray: rfDict, array entry nil") + } + + o, err := xRefTable.Dereference(v) + if err != nil { + return err + } + + if o == nil { + return errors.New("pdfcpu: validateRFDictFilesArray: rfDict, array entry nil") + } + + if k%2 > 0 { + + _, ok := o.(pdf.StringLiteral) + if !ok { + return errors.New("pdfcpu: validateRFDictFilesArray: rfDict, array entry corrupt") + } + + } else { + + // value must be embedded file stream dict + // see 7.11.4 + sd, err := validateStreamDict(xRefTable, o) + if err != nil { + return err + } + + err = validateEmbeddedFileStreamDict(xRefTable, sd) + if err != nil { + return err + } + + } + } + + return nil +} + +func validateFileSpecDictEntriesEFAndRF(xRefTable *pdf.XRefTable, efDict, rfDict pdf.Dict) error { + + // EF only or EF and RF + + if efDict == nil { + return errors.Errorf("pdfcpu: validateFileSpecEntriesEFAndRF: missing required efDict.") + } + + err := validateFileSpecDictEntryEFDict(xRefTable, efDict) + if err != nil { + return err + } + + if rfDict != nil { + + for k, val := range rfDict { + + if _, ok := efDict.Find(k); !ok { + return errors.Errorf("pdfcpu: validateFileSpecEntriesEFAndRF: rfDict entry=%s missing corresponding efDict entry\n", k) + } + + // value must be related files array. + // see 7.11.4.2 + a, err := xRefTable.DereferenceArray(val) + if err != nil { + return err + } + + if a == nil { + continue + } + + err = validateRFDictFilesArray(xRefTable, a) + if err != nil { + return err + } + + } + + } + + return nil +} + +func validateFileSpecDictType(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + if d.Type() == nil || (*d.Type() != "Filespec" && (xRefTable.ValidationMode == pdf.ValidationRelaxed && *d.Type() != "F")) { + return errors.New("pdfcpu: validateFileSpecDictType: missing type: FileSpec") + } + + return nil +} + +func requiredF(dosFound, macFound, unixFound bool) bool { + return !dosFound && !macFound && !unixFound +} + +func validateFileSpecDictEFAndRF(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // RF, optional, dict of related files arrays, since V1.3 + rfDict, err := validateDictEntry(xRefTable, d, dictName, "RF", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // EF, required if RF present, dict of embedded file streams, since 1.3 + efDict, err := validateDictEntry(xRefTable, d, dictName, "EF", rfDict != nil, pdf.V13, nil) + if err != nil { + return err + } + + // Type, required if EF present, name + validate := func(s string) bool { + return s == "Filespec" || (xRefTable.ValidationMode == pdf.ValidationRelaxed && s == "F") + } + _, err = validateNameEntry(xRefTable, d, dictName, "Type", efDict != nil, pdf.V10, validate) + if err != nil { + return err + } + + // if EF present, Type "FileSpec" is required + if efDict != nil { + + err = validateFileSpecDictType(xRefTable, d) + if err != nil { + return err + } + + err = validateFileSpecDictEntriesEFAndRF(xRefTable, efDict, rfDict) + + } + + return err +} + +func validateFileSpecDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "fileSpecDict" + + // FS, optional, name + fsName, err := validateNameEntry(xRefTable, d, dictName, "FS", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // DOS, byte string, optional, obsolescent. + _, dosFound := d.Find("DOS") + + // Mac, byte string, optional, obsolescent. + _, macFound := d.Find("Mac") + + // Unix, byte string, optional, obsolescent. + _, unixFound := d.Find("Unix") + + // F, file spec string + validate := validateFileSpecString + if fsName != nil && fsName.Value() == "URL" { + validate = validateURLString + } + + _, err = validateStringEntry(xRefTable, d, dictName, "F", requiredF(dosFound, macFound, unixFound), pdf.V10, validate) + if err != nil { + return err + } + + // UF, optional, text string + sinceVersion := pdf.V17 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V14 + } + _, err = validateStringEntry(xRefTable, d, dictName, "UF", OPTIONAL, sinceVersion, validateFileSpecString) + if err != nil { + return err + } + + // ID, optional, array of strings + _, err = validateStringArrayEntry(xRefTable, d, dictName, "ID", OPTIONAL, pdf.V11, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + // V, optional, boolean, since V1.2 + _, err = validateBooleanEntry(xRefTable, d, dictName, "V", OPTIONAL, pdf.V12, nil) + if err != nil { + return err + } + + err = validateFileSpecDictEFAndRF(xRefTable, d, dictName) + if err != nil { + return err + } + + // Desc, optional, text string, since V1.6 + sinceVersion = pdf.V16 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V10 + } + _, err = validateStringEntry(xRefTable, d, dictName, "Desc", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // CI, optional, collection item dict, since V1.7 + _, err = validateDictEntry(xRefTable, d, dictName, "CI", OPTIONAL, pdf.V17, nil) + + return err +} + +func validateFileSpecification(xRefTable *pdf.XRefTable, o pdf.Object) (pdf.Object, error) { + + // See 7.11.4 + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + + switch o := o.(type) { + + case pdf.StringLiteral: + s := o.Value() + if !validateFileSpecString(s) { + return nil, errors.Errorf("pdfcpu: validateFileSpecification: invalid file spec string: %s", s) + } + + case pdf.HexLiteral: + s := o.Value() + if !validateFileSpecString(s) { + return nil, errors.Errorf("pdfcpu: validateFileSpecification: invalid file spec string: %s", s) + } + + case pdf.Dict: + err = validateFileSpecDict(xRefTable, o) + if err != nil { + return nil, err + } + + default: + return nil, errors.Errorf("pdfcpu: validateFileSpecification: invalid type") + + } + + return o, nil +} + +func validateURLSpecification(xRefTable *pdf.XRefTable, o pdf.Object) (pdf.Object, error) { + + // See 7.11.4 + + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return nil, err + } + + if d == nil { + return nil, errors.New("pdfcpu: validateURLSpecification: missing dict") + } + + dictName := "urlSpec" + + // FS, required, name + _, err = validateNameEntry(xRefTable, d, dictName, "FS", REQUIRED, pdf.V10, func(s string) bool { return s == "URL" }) + if err != nil { + return nil, err + } + + // F, required, string, URL (Internet RFC 1738) + _, err = validateStringEntry(xRefTable, d, dictName, "F", REQUIRED, pdf.V10, validateURLString) + + return o, err +} + +func validateFileSpecEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) (pdf.Object, error) { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return nil, err + } + + err = xRefTable.ValidateVersion("fileSpec", sinceVersion) + if err != nil { + return nil, err + } + + return validateFileSpecification(xRefTable, o) +} + +func validateURLSpecEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) (pdf.Object, error) { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return nil, err + } + + err = xRefTable.ValidateVersion("URLSpec", sinceVersion) + if err != nil { + return nil, err + } + + return validateURLSpecification(xRefTable, o) +} + +func validateFileSpecificationOrFormObject(xRefTable *pdf.XRefTable, obj pdf.Object) error { + + sd, ok := obj.(pdf.StreamDict) + if ok { + return validateFormStreamDict(xRefTable, &sd) + } + + _, err := validateFileSpecification(xRefTable, obj) + + return err +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/font.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/font.go new file mode 100644 index 0000000..ad9afd6 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/font.go @@ -0,0 +1,1014 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + "github.com/pdfcpu/pdfcpu/pkg/log" + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateStandardType1Font(s string) bool { + + return pdf.MemberOf(s, []string{"Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic", + "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique", + "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", + "Symbol", "ZapfDingbats"}) +} + +func validateFontFile3SubType(sd *pdf.StreamDict, fontType string) error { + + // Hint about used font program. + dictSubType := sd.Subtype() + + if dictSubType == nil { + return errors.New("pdfcpu: validateFontFile3SubType: missing Subtype") + } + + switch fontType { + case "Type1": + if *dictSubType != "Type1C" && *dictSubType != "OpenType" { + return errors.Errorf("pdfcpu: validateFontFile3SubType: Type1: unexpected Subtype %s", *dictSubType) + } + + case "MMType1": + if *dictSubType != "Type1C" { + return errors.Errorf("pdfcpu: validateFontFile3SubType: MMType1: unexpected Subtype %s", *dictSubType) + } + + case "CIDFontType0": + if *dictSubType != "CIDFontType0C" && *dictSubType != "OpenType" { + return errors.Errorf("pdfcpu: validateFontFile3SubType: CIDFontType0: unexpected Subtype %s", *dictSubType) + } + + case "CIDFontType2", "TrueType": + if *dictSubType != "OpenType" { + return errors.Errorf("pdfcpu: validateFontFile3SubType: %s: unexpected Subtype %s", fontType, *dictSubType) + } + } + + return nil +} + +func validateFontFile(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, fontType string, required bool, sinceVersion pdf.Version) error { + + sd, err := validateStreamDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || sd == nil { + return err + } + + // Process font file stream dict entries. + + // SubType + if entryName == "FontFile3" { + err = validateFontFile3SubType(sd, fontType) + if err != nil { + return err + } + + } + + dName := "fontFileStreamDict" + compactFontFormat := entryName == "FontFile3" + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dName, "Length1", (fontType == "Type1" || fontType == "TrueType") && !compactFontFormat, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dName, "Length2", fontType == "Type1" && !compactFontFormat, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dName, "Length3", fontType == "Type1" && !compactFontFormat, pdf.V10, nil) + if err != nil { + return err + } + + // Metadata, stream, optional, since 1.4 + return validateMetadata(xRefTable, sd.Dict, OPTIONAL, pdf.V14) +} + +func validateFontDescriptorType(xRefTable *pdf.XRefTable, d pdf.Dict) (err error) { + + dictType := d.Type() + + if dictType == nil { + + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + log.Validate.Println("validateFontDescriptor: missing entry \"Type\"") + } else { + return errors.New("pdfcpu: validateFontDescriptor: missing entry \"Type\"") + } + + } + + if dictType != nil && *dictType != "FontDescriptor" && *dictType != "Font" { + return errors.New("pdfcpu: validateFontDescriptor: corrupt font descriptor dict") + } + + return nil +} + +func validateFontDescriptorPart1(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, fontDictType string) error { + + err := validateFontDescriptorType(xRefTable, d) + if err != nil { + return err + } + + _, err = validateNameEntry(xRefTable, d, dictName, "FontName", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + sinceVersion := pdf.V15 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + _, err = validateStringEntry(xRefTable, d, dictName, "FontFamily", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + sinceVersion = pdf.V15 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + _, err = validateNameEntry(xRefTable, d, dictName, "FontStretch", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + sinceVersion = pdf.V15 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + _, err = validateNumberEntry(xRefTable, d, dictName, "FontWeight", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, d, dictName, "Flags", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateRectangleEntry(xRefTable, d, dictName, "FontBBox", fontDictType != "Type3", pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, d, dictName, "ItalicAngle", REQUIRED, pdf.V10, nil) + + return err +} + +func validateFontDescriptorPart2(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, fontDictType string) error { + + _, err := validateNumberEntry(xRefTable, d, dictName, "Ascent", fontDictType != "Type3", pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, d, dictName, "Descent", fontDictType != "Type3", pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, d, dictName, "Leading", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, d, dictName, "CapHeight", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, d, dictName, "XHeight", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + required := fontDictType != "Type3" + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + required = false + } + _, err = validateNumberEntry(xRefTable, d, dictName, "StemV", required, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, d, dictName, "StemH", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, d, dictName, "AvgWidth", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, d, dictName, "MaxWidth", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, d, dictName, "MissingWidth", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + err = validateFontDescriptorFontFile(xRefTable, d, dictName, fontDictType) + if err != nil { + return err + } + + _, err = validateStringEntry(xRefTable, d, dictName, "CharSet", OPTIONAL, pdf.V11, nil) + + return err +} + +func validateFontDescriptorFontFile(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, fontDictType string) (err error) { + + switch fontDictType { + + case "Type1", "MMType1": + + err = validateFontFile(xRefTable, d, dictName, "FontFile", fontDictType, OPTIONAL, pdf.V10) + if err != nil { + return err + } + + err = validateFontFile(xRefTable, d, dictName, "FontFile3", fontDictType, OPTIONAL, pdf.V12) + + case "TrueType", "CIDFontType2": + err = validateFontFile(xRefTable, d, dictName, "FontFile2", fontDictType, OPTIONAL, pdf.V11) + + case "CIDFontType0": + err = validateFontFile(xRefTable, d, dictName, "FontFile3", fontDictType, OPTIONAL, pdf.V13) + + case "Type3": // No fontfile. + + default: + return errors.Errorf("pdfcpu: unknown fontDictType: %s\n", fontDictType) + + } + + return err +} + +func validateFontDescriptor(xRefTable *pdf.XRefTable, d pdf.Dict, fontDictName string, fontDictType string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, fontDictName, "FontDescriptor", required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + dictName := "fdDict" + + // Process font descriptor dict + + err = validateFontDescriptorPart1(xRefTable, d1, dictName, fontDictType) + if err != nil { + return err + } + + err = validateFontDescriptorPart2(xRefTable, d1, dictName, fontDictType) + if err != nil { + return err + } + + if fontDictType == "CIDFontType0" || fontDictType == "CIDFontType2" { + + validateStyleDict := func(d pdf.Dict) bool { + + // see 9.8.3.2 + + if d.Len() != 1 { + return false + } + + _, found := d.Find("Panose") + + return found + } + + // Style, optional, dict + _, err = validateDictEntry(xRefTable, d1, dictName, "Style", OPTIONAL, pdf.V10, validateStyleDict) + if err != nil { + return err + } + + // Lang, optional, name + _, err = validateNameEntry(xRefTable, d1, dictName, "Lang", OPTIONAL, pdf.V15, nil) + if err != nil { + return err + } + + // FD, optional, dict + _, err = validateDictEntry(xRefTable, d1, dictName, "FD", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // CIDSet, optional, stream + _, err = validateStreamDictEntry(xRefTable, d1, dictName, "CIDSet", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + } + + return nil +} + +func validateFontEncoding(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool) error { + + entryName := "Encoding" + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, pdf.V10) + if err != nil || o == nil { + return err + } + + encodings := []string{"MacRomanEncoding", "MacExpertEncoding", "WinAnsiEncoding"} + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + encodings = append(encodings, "StandardEncoding") + } + + switch o := o.(type) { + + case pdf.Name: + s := o.Value() + validateFontEncodingName := func(s string) bool { + return pdf.MemberOf(s, encodings) + } + if !validateFontEncodingName(s) { + return errors.Errorf("validateFontEncoding: invalid Encoding name: %s\n", s) + } + + case pdf.Dict: + // no further processing + + default: + return errors.Errorf("validateFontEncoding: dict=%s corrupt entry \"%s\"\n", dictName, entryName) + + } + + return nil +} + +func validateTrueTypeFontDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // see 9.6.3 + dictName := "trueTypeFontDict" + + // Name, name, obsolet and should not be used. + + // BaseFont, required, name + _, err := validateNameEntry(xRefTable, d, dictName, "BaseFont", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // FirstChar, required, integer + required := REQUIRED + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + required = OPTIONAL + } + _, err = validateIntegerEntry(xRefTable, d, dictName, "FirstChar", required, pdf.V10, nil) + if err != nil { + return err + } + + // LastChar, required, integer + required = REQUIRED + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + required = OPTIONAL + } + _, err = validateIntegerEntry(xRefTable, d, dictName, "LastChar", required, pdf.V10, nil) + if err != nil { + return err + } + + // Widths, array of numbers. + required = REQUIRED + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + required = OPTIONAL + } + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Widths", required, pdf.V10, nil) + if err != nil { + return err + } + + // FontDescriptor, required, dictionary + required = REQUIRED + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + required = OPTIONAL + } + err = validateFontDescriptor(xRefTable, d, dictName, "TrueType", required, pdf.V10) + if err != nil { + return err + } + + // Encoding, optional, name or dict + err = validateFontEncoding(xRefTable, d, dictName, OPTIONAL) + if err != nil { + return err + } + + // ToUnicode, optional, stream + _, err = validateStreamDictEntry(xRefTable, d, dictName, "ToUnicode", OPTIONAL, pdf.V12, nil) + + return err +} + +func validateCIDToGIDMap(xRefTable *pdf.XRefTable, o pdf.Object) error { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + s := o.Value() + if s != "Identity" { + return errors.Errorf("pdfcpu: validateCIDToGIDMap: invalid name: %s - must be \"Identity\"\n", s) + } + + case pdf.StreamDict: + // no further processing + + default: + return errors.New("pdfcpu: validateCIDToGIDMap: corrupt entry") + + } + + return nil +} + +func validateCIDFontGlyphWidths(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + a, err := validateArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || a == nil { + return err + } + + for i, o := range a { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o.(type) { + + case pdf.Integer: + // no further processing. + + case pdf.Float: + // no further processing + + case pdf.Array: + _, err = validateNumberArray(xRefTable, o) + if err != nil { + return err + } + + default: + return errors.Errorf("validateCIDFontGlyphWidths: dict=%s entry=%s invalid type at index %d\n", dictName, entryName, i) + } + + } + + return nil +} + +func validateCIDFontDictEntryCIDSystemInfo(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, "CIDSystemInfo", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateCIDSystemInfoDict(xRefTable, d1) + + } + + return err +} + +func validateCIDFontDictEntryCIDToGIDMap(xRefTable *pdf.XRefTable, d pdf.Dict, isCIDFontType2 bool) error { + + if o, found := d.Find("CIDToGIDMap"); found { + + if !isCIDFontType2 { + return errors.New("pdfcpu: validateCIDFontDict: entry CIDToGIDMap not allowed - must be CIDFontType2") + } + + err := validateCIDToGIDMap(xRefTable, o) + if err != nil { + return err + } + + } + + return nil +} + +func validateCIDFontDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // see 9.7.4 + + dictName := "CIDFontDict" + + // Type, required, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", REQUIRED, pdf.V10, func(s string) bool { return s == "Font" }) + if err != nil { + return err + } + + var isCIDFontType2 bool + var fontType string + + // Subtype, required, name + subType, err := validateNameEntry(xRefTable, d, dictName, "Subtype", REQUIRED, pdf.V10, func(s string) bool { return s == "CIDFontType0" || s == "CIDFontType2" }) + if err != nil { + return err + } + + isCIDFontType2 = *subType == "CIDFontType2" + fontType = subType.Value() + + // BaseFont, required, name + _, err = validateNameEntry(xRefTable, d, dictName, "BaseFont", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // CIDSystemInfo, required, dict + err = validateCIDFontDictEntryCIDSystemInfo(xRefTable, d, "CIDFontDict") + if err != nil { + return err + } + + // FontDescriptor, required, dict + err = validateFontDescriptor(xRefTable, d, dictName, fontType, REQUIRED, pdf.V10) + if err != nil { + return err + } + + // DW, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "DW", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // W, optional, array + err = validateCIDFontGlyphWidths(xRefTable, d, dictName, "W", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // DW2, optional, array + // An array of two numbers specifying the default metrics for vertical writing. + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "DW2", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + // W2, optional, array + err = validateCIDFontGlyphWidths(xRefTable, d, dictName, "W2", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // CIDToGIDMap, stream or (name /Identity) + // optional, Type 2 CIDFonts with embedded associated TrueType font program only. + return validateCIDFontDictEntryCIDToGIDMap(xRefTable, d, isCIDFontType2) +} + +func validateDescendantFonts(xRefTable *pdf.XRefTable, d pdf.Dict, fontDictName string, required bool) error { + + // A one-element array holding a CID font dictionary. + + a, err := validateArrayEntry(xRefTable, d, fontDictName, "DescendantFonts", required, pdf.V10, func(a pdf.Array) bool { return len(a) == 1 }) + if err != nil || a == nil { + return err + } + + d1, err := xRefTable.DereferenceDict(a[0]) + if err != nil { + return err + } + + if d1 == nil { + if required { + return errors.Errorf("validateDescendantFonts: dict=%s required descendant font dict missing.\n", fontDictName) + } + return nil + } + + return validateCIDFontDict(xRefTable, d1) +} + +func validateType0FontDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "type0FontDict" + + // BaseFont, required, name + _, err := validateNameEntry(xRefTable, d, dictName, "BaseFont", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // Encoding, required, name or CMap stream dict + err = validateType0FontEncoding(xRefTable, d, dictName, REQUIRED) + if err != nil { + return err + } + + // DescendantFonts: one-element array specifying the CIDFont dictionary that is the descendant of this Type 0 font, required. + err = validateDescendantFonts(xRefTable, d, dictName, REQUIRED) + if err != nil { + return err + } + + // ToUnicode, optional, CMap stream dict + _, err = validateStreamDictEntry(xRefTable, d, dictName, "ToUnicode", OPTIONAL, pdf.V12, nil) + + return err +} + +func validateType1FontDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // see 9.6.2 + + dictName := "type1FontDict" + + // Name, name, obsolet and should not be used. + + // BaseFont, required, name + fontName, err := validateNameEntry(xRefTable, d, dictName, "BaseFont", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + fn := (*fontName).Value() + required := xRefTable.Version() >= pdf.V15 || !validateStandardType1Font(fn) + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + required = !validateStandardType1Font(fn) && fn != "Arial" + } + // FirstChar, required except for standard 14 fonts. since 1.5 always required, integer + fc, err := validateIntegerEntry(xRefTable, d, dictName, "FirstChar", required, pdf.V10, nil) + if err != nil { + return err + } + + if !required && fc != nil { + // For the standard 14 fonts, the entries FirstChar, LastChar, Widths and FontDescriptor shall either all be present or all be absent. + if xRefTable.ValidationMode == pdf.ValidationStrict { + required = true + } else { + // relaxed: do nothing + } + } + + // LastChar, required except for standard 14 fonts. since 1.5 always required, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "LastChar", required, pdf.V10, nil) + if err != nil { + return err + } + + // Widths, required except for standard 14 fonts. since 1.5 always required, array of numbers + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Widths", required, pdf.V10, nil) + if err != nil { + return err + } + + // FontDescriptor, required since version 1.5; required unless standard font for version < 1.5, dict + err = validateFontDescriptor(xRefTable, d, dictName, "Type1", required, pdf.V10) + if err != nil { + return err + } + + // Encoding, optional, name or dict + err = validateFontEncoding(xRefTable, d, dictName, OPTIONAL) + if err != nil { + return err + } + + // ToUnicode, optional, stream + _, err = validateStreamDictEntry(xRefTable, d, dictName, "ToUnicode", OPTIONAL, pdf.V12, nil) + + return err +} + +func validateCharProcsDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, "CharProcs", required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + for _, v := range d1 { + + _, _, err = xRefTable.DereferenceStreamDict(v) + if err != nil { + return err + } + + } + + return nil +} + +func validateUseCMapEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool, sinceVersion pdf.Version) error { + + entryName := "UseCMap" + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + // no further processing + + case pdf.StreamDict: + err = validateCMapStreamDict(xRefTable, &o) + if err != nil { + return err + } + + default: + return errors.Errorf("validateUseCMapEntry: dict=%s corrupt entry \"%s\"\n", dictName, entryName) + + } + + return nil +} + +func validateCIDSystemInfoDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "CIDSystemInfoDict" + + // Registry, required, ASCII string + _, err := validateStringEntry(xRefTable, d, dictName, "Registry", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // Ordering, required, ASCII string + _, err = validateStringEntry(xRefTable, d, dictName, "Ordering", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // Supplement, required, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "Supplement", REQUIRED, pdf.V10, nil) + + return err +} + +func validateCMapStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict) error { + + // See table 120 + + dictName := "CMapStreamDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, sd.Dict, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "CMap" }) + if err != nil { + return err + } + + // CMapName, required, name + _, err = validateNameEntry(xRefTable, sd.Dict, dictName, "CMapName", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // CIDFontType0SystemInfo, required, dict + d, err := validateDictEntry(xRefTable, sd.Dict, dictName, "CIDSystemInfo", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + if d != nil { + err = validateCIDSystemInfoDict(xRefTable, d) + if err != nil { + return err + } + } + + // WMode, optional, integer, 0 or 1 + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "WMode", OPTIONAL, pdf.V10, func(i int) bool { return i == 0 || i == 1 }) + if err != nil { + return err + } + + // UseCMap, name or cmap stream dict, optional. + // If present, the referencing CMap shall specify only + // the character mappings that differ from the referenced CMap. + return validateUseCMapEntry(xRefTable, sd.Dict, dictName, OPTIONAL, pdf.V10) +} + +func validateType0FontEncoding(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool) error { + + entryName := "Encoding" + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, pdf.V10) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + // no further processing + + case pdf.StreamDict: + err = validateCMapStreamDict(xRefTable, &o) + + default: + err = errors.Errorf("validateType0FontEncoding: dict=%s corrupt entry \"Encoding\"\n", dictName) + + } + + return err +} + +func validateType3FontDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // see 9.6.5 + + dictName := "type3FontDict" + + // Name, name, obsolet and should not be used. + + // FontBBox, required, rectangle + _, err := validateRectangleEntry(xRefTable, d, dictName, "FontBBox", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // FontMatrix, required, number array + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "FontMatrix", REQUIRED, pdf.V10, func(a pdf.Array) bool { return len(a) == 6 }) + if err != nil { + return err + } + + // CharProcs, required, dict + err = validateCharProcsDict(xRefTable, d, dictName, REQUIRED, pdf.V10) + if err != nil { + return err + } + + // Encoding, required, name or dict + err = validateFontEncoding(xRefTable, d, dictName, REQUIRED) + if err != nil { + return err + } + + // FirstChar, required, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "FirstChar", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // LastChar, required, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "LastChar", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // Widths, required, array of number + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Widths", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // FontDescriptor, required since version 1.5 for tagged PDF documents, dict + sinceVersion := pdf.V15 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + err = validateFontDescriptor(xRefTable, d, dictName, "Type3", xRefTable.Tagged, sinceVersion) + if err != nil { + return err + } + + // Resources, optional, dict, since V1.2 + d1, err := validateDictEntry(xRefTable, d, dictName, "Resources", OPTIONAL, pdf.V12, nil) + if err != nil { + return err + } + if d1 != nil { + _, err := validateResourceDict(xRefTable, d1) + if err != nil { + return err + } + } + + // ToUnicode, optional, stream + _, err = validateStreamDictEntry(xRefTable, d, dictName, "ToUnicode", OPTIONAL, pdf.V12, nil) + + return err +} + +func validateFontDict(xRefTable *pdf.XRefTable, o pdf.Object) (err error) { + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + if len(d) == 0 { + return nil + } + } + + if d.Type() == nil || *d.Type() != "Font" { + return errors.New("pdfcpu: validateFontDict: corrupt font dict") + } + + subtype := d.Subtype() + if subtype == nil { + return errors.New("pdfcpu: validateFontDict: missing Subtype") + } + + switch *subtype { + + case "TrueType": + err = validateTrueTypeFontDict(xRefTable, d) + + case "Type0": + err = validateType0FontDict(xRefTable, d) + + case "Type1": + err = validateType1FontDict(xRefTable, d) + + case "MMType1": + err = validateType1FontDict(xRefTable, d) + + case "Type3": + err = validateType3FontDict(xRefTable, d) + + default: + return errors.Errorf("pdfcpu: validateFontDict: unknown Subtype: %s\n", *subtype) + + } + + return err +} + +func validateFontResourceDict(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // Version check + err := xRefTable.ValidateVersion("fontResourceDict", sinceVersion) + if err != nil { + return err + } + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + // Iterate over font resource dict + for _, obj := range d { + + // Process fontDict + err = validateFontDict(xRefTable, obj) + if err != nil { + return err + } + + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/function.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/function.go new file mode 100644 index 0000000..e3f580f --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/function.go @@ -0,0 +1,239 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// see 7.10 Functions + +func validateExponentialInterpolationFunctionDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "exponentialInterpolationFunctionDict" + + // Version check + err := xRefTable.ValidateVersion(dictName, pdf.V13) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Domain", REQUIRED, pdf.V13, nil) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Range", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "C0", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "C1", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, d, dictName, "N", REQUIRED, pdf.V13, nil) + + return err +} + +func validateStitchingFunctionDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "stitchingFunctionDict" + + // Version check + err := xRefTable.ValidateVersion(dictName, pdf.V13) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Domain", REQUIRED, pdf.V13, nil) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Range", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + _, err = validateFunctionArrayEntry(xRefTable, d, dictName, "Functions", REQUIRED, pdf.V13, nil) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Bounds", REQUIRED, pdf.V13, nil) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Encode", REQUIRED, pdf.V13, nil) + + return err +} + +func validateSampledFunctionStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict) error { + + dictName := "sampledFunctionStreamDict" + + // Version check + err := xRefTable.ValidateVersion(dictName, pdf.V12) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, sd.Dict, dictName, "Domain", REQUIRED, pdf.V12, nil) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, sd.Dict, dictName, "Range", REQUIRED, pdf.V12, nil) + if err != nil { + return err + } + + _, err = validateIntegerArrayEntry(xRefTable, sd.Dict, dictName, "Size", REQUIRED, pdf.V12, nil) + if err != nil { + return err + } + + validate := func(i int) bool { return pdf.IntMemberOf(i, []int{1, 2, 4, 8, 12, 16, 24, 32}) } + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "BitsPerSample", REQUIRED, pdf.V12, validate) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "Order", OPTIONAL, pdf.V12, func(i int) bool { return i == 1 || i == 3 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, sd.Dict, dictName, "Encode", OPTIONAL, pdf.V12, nil) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, sd.Dict, dictName, "Decode", OPTIONAL, pdf.V12, nil) + + return err +} + +func validatePostScriptCalculatorFunctionStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict) error { + + dictName := "postScriptCalculatorFunctionStreamDict" + + // Version check + err := xRefTable.ValidateVersion(dictName, pdf.V13) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, sd.Dict, dictName, "Domain", REQUIRED, pdf.V13, nil) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, sd.Dict, dictName, "Range", REQUIRED, pdf.V13, nil) + + return err +} + +func processFunctionDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + funcType, err := validateIntegerEntry(xRefTable, d, "functionDict", "FunctionType", REQUIRED, pdf.V10, func(i int) bool { return i == 2 || i == 3 }) + if err != nil { + return err + } + + switch *funcType { + + case 2: + err = validateExponentialInterpolationFunctionDict(xRefTable, d) + + case 3: + err = validateStitchingFunctionDict(xRefTable, d) + + } + + return err +} + +func processFunctionStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict) error { + + funcType, err := validateIntegerEntry(xRefTable, sd.Dict, "functionDict", "FunctionType", REQUIRED, pdf.V10, func(i int) bool { return i == 0 || i == 4 }) + if err != nil { + return err + } + + switch *funcType { + case 0: + err = validateSampledFunctionStreamDict(xRefTable, sd) + + case 4: + err = validatePostScriptCalculatorFunctionStreamDict(xRefTable, sd) + + } + + return err +} + +func processFunction(xRefTable *pdf.XRefTable, o pdf.Object) (err error) { + + // Function dict: dict or stream dict with required entry "FunctionType" (integer): + // 0: Sampled function (stream dict) + // 2: Exponential interpolation function (dict) + // 3: Stitching function (dict) + // 4: PostScript calculator function (stream dict), since V1.3 + + switch o := o.(type) { + + case pdf.Dict: + + // process function 2,3 + err = processFunctionDict(xRefTable, o) + + case pdf.StreamDict: + + // process function 0,4 + err = processFunctionStreamDict(xRefTable, &o) + + default: + return errors.New("pdfcpu: processFunction: obj must be dict or stream dict") + } + + return err +} + +func validateFunction(xRefTable *pdf.XRefTable, o pdf.Object) error { + + o, err := xRefTable.Dereference(o) + if err != nil { + return err + } + if o == nil { + return errors.New("pdfcpu: validateFunction: missing object") + } + + return processFunction(xRefTable, o) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/info.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/info.go new file mode 100644 index 0000000..1ce3e28 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/info.go @@ -0,0 +1,202 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + "unicode/utf8" + + "github.com/pdfcpu/pdfcpu/pkg/log" + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// DocumentProperty ensures a property name that may be modified. +func DocumentProperty(s string) bool { + return !pdf.MemberOf(s, []string{"Keywords", "Creator", "Producer", "CreationDate", "ModDate", "Trapped"}) +} + +func handleDefault(xRefTable *pdf.XRefTable, o pdf.Object) (string, error) { + + s, err := xRefTable.DereferenceStringOrHexLiteral(o, pdf.V10, nil) + if err == nil { + return s, nil + } + + if xRefTable.ValidationMode == pdf.ValidationStrict { + return "", err + } + + _, err = xRefTable.Dereference(o) + return "", err +} + +func validateInfoDictDate(xRefTable *pdf.XRefTable, o pdf.Object) (s string, err error) { + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + return validateString(xRefTable, o, nil) + } + return validateDateObject(xRefTable, o, pdf.V10) +} + +func validateInfoDictTrapped(xRefTable *pdf.XRefTable, o pdf.Object) error { + + sinceVersion := pdf.V13 + + validate := func(s string) bool { return pdf.MemberOf(s, []string{"True", "False", "Unknown"}) } + + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + validate = func(s string) bool { + return pdf.MemberOf(s, []string{"True", "False", "Unknown", "true", "false", "unknown"}) + } + } + + _, err := xRefTable.DereferenceName(o, sinceVersion, validate) + if err == nil { + return nil + } + + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + _, err = xRefTable.DereferenceBoolean(o, sinceVersion) + } + + return err +} + +func handleProperties(xRefTable *pdf.XRefTable, key string, val pdf.Object) error { + if !utf8.ValidString(key) { + key = pdf.CP1252ToUTF8(key) + } + s, err := handleDefault(xRefTable, val) + if err != nil { + return err + } + if s != "" { + xRefTable.Properties[key] = s + } + return nil +} + +func validateDocInfoDictEntry(xRefTable *pdf.XRefTable, k string, v pdf.Object) (bool, error) { + var ( + err error + hasModDate bool + ) + + switch k { + + // text string, opt, since V1.1 + case "Title": + xRefTable.Title, err = xRefTable.DereferenceStringOrHexLiteral(v, pdf.V11, nil) + + // text string, optional + case "Author": + xRefTable.Author, err = xRefTable.DereferenceStringOrHexLiteral(v, pdf.V10, nil) + + // text string, optional, since V1.1 + case "Subject": + xRefTable.Subject, err = xRefTable.DereferenceStringOrHexLiteral(v, pdf.V11, nil) + + // text string, optional, since V1.1 + case "Keywords": + xRefTable.Keywords, err = xRefTable.DereferenceStringOrHexLiteral(v, pdf.V11, nil) + + // text string, optional + case "Creator": + xRefTable.Creator, err = xRefTable.DereferenceStringOrHexLiteral(v, pdf.V10, nil) + + // text string, optional + case "Producer": + xRefTable.Producer, err = xRefTable.DereferenceStringOrHexLiteral(v, pdf.V10, nil) + + // date, optional + case "CreationDate": + xRefTable.CreationDate, err = validateInfoDictDate(xRefTable, v) + + // date, required if PieceInfo is present in document catalog. + case "ModDate": + hasModDate = true + xRefTable.ModDate, err = validateInfoDictDate(xRefTable, v) + + // name, optional, since V1.3 + case "Trapped": + err = validateInfoDictTrapped(xRefTable, v) + + // text string, optional + default: + err = handleProperties(xRefTable, k, v) + } + + return hasModDate, err +} + +func validateDocumentInfoDict(xRefTable *pdf.XRefTable, obj pdf.Object) (bool, error) { + // Document info object is optional. + d, err := xRefTable.DereferenceDict(obj) + if err != nil || d == nil { + return false, err + } + + hasModDate := false + + for k, v := range d { + + hmd, err := validateDocInfoDictEntry(xRefTable, k, v) + + if err == pdf.ErrInvalidUTF16BE { + // Hack for #264: 🤢 where iText modifies a correct UTF-16BE string + // and carries over the UTF16 BOM when rewriting a PDFDocEncoded string. + err = nil + } + + if err != nil { + return false, err + } + + if !hasModDate && hmd { + hasModDate = true + } + } + + return hasModDate, nil +} + +func validateDocumentInfoObject(xRefTable *pdf.XRefTable) error { + + // Document info object is optional. + if xRefTable.Info == nil { + return nil + } + + log.Validate.Println("*** validateDocumentInfoObject begin ***") + + hasModDate, err := validateDocumentInfoDict(xRefTable, *xRefTable.Info) + if err != nil { + return err + } + + hasPieceInfo, err := xRefTable.CatalogHasPieceInfo() + if err != nil { + return err + } + + if hasPieceInfo && !hasModDate { + return errors.Errorf("validateDocumentInfoObject: missing required entry \"ModDate\"") + } + + log.Validate.Println("*** validateDocumentInfoObject end ***") + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/media.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/media.go new file mode 100644 index 0000000..e1ca771 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/media.go @@ -0,0 +1,1047 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + +func validateMinimumBitDepthDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see table 269 + + dictName := "minBitDepthDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "MinBitDepth" }) + if err != nil { + return err + } + + // V, required, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "V", REQUIRED, sinceVersion, func(i int) bool { return i >= 0 }) + if err != nil { + return err + } + + // M, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "M", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateMinimumScreenSizeDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see table 269 + + dictName := "minBitDepthDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "MinScreenSize" }) + if err != nil { + return err + } + + // V, required, integer array, length 2 + _, err = validateIntegerArrayEntry(xRefTable, d, dictName, "V", REQUIRED, sinceVersion, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + // M, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "M", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateSoftwareIdentifierDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see table 292 + + dictName := "swIdDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "SoftwareIdentifier" }) + if err != nil { + return err + } + + // U, required, ASCII string + _, err = validateStringEntry(xRefTable, d, dictName, "U", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + // L, optional, array + _, err = validateArrayEntry(xRefTable, d, dictName, "L", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // LI, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "LI", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // H, optional, array + _, err = validateArrayEntry(xRefTable, d, dictName, "H", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // HI, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "HI", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // OS, optional, array + _, err = validateStringArrayEntry(xRefTable, d, dictName, "OS", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateMediaCriteriaDictEntryD(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, "D", required, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateMinimumBitDepthDict(xRefTable, d1, sinceVersion) + } + + return err +} + +func validateMediaCriteriaDictEntryZ(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, "Z", required, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateMinimumScreenSizeDict(xRefTable, d1, sinceVersion) + } + + return err +} + +func validateMediaCriteriaDictEntryV(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool, sinceVersion pdf.Version) error { + + a, err := validateArrayEntry(xRefTable, d, dictName, "V", required, sinceVersion, nil) + if err != nil { + return err + } + + if a != nil { + + for _, v := range a { + + if v == nil { + continue + } + + d, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + + if d != nil { + err = validateSoftwareIdentifierDict(xRefTable, d, sinceVersion) + if err != nil { + return err + } + } + + } + + } + + return nil +} + +func validateMediaCriteriaDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see table 268 + + dictName := "mediaCritDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "MediaCriteria" }) + if err != nil { + return err + } + + // A, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "A", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // C, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "C", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // O, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "O", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // S, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "S", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // R, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "R", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // D, optional, dict + err = validateMediaCriteriaDictEntryD(xRefTable, d, dictName, OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // Z, optional, dict + err = validateMediaCriteriaDictEntryZ(xRefTable, d, dictName, OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // V, optional, array + err = validateMediaCriteriaDictEntryV(xRefTable, d, dictName, OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // P, optional, array + _, err = validateNameArrayEntry(xRefTable, d, dictName, "P", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 1 || len(a) == 2 }) + if err != nil { + return err + } + + // L, optional, array + _, err = validateStringArrayEntry(xRefTable, d, dictName, "L", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateMediaPermissionsDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, sinceVersion pdf.Version) error { + + // see table 275 + d1, err := validateDictEntry(xRefTable, d, dictName, "P", OPTIONAL, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + dictName = "mediaPermissionDict" + + // Type, optional, name + _, err = validateNameEntry(xRefTable, d1, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "MediaPermissions" }) + if err != nil { + return err + } + + // TF, optional, ASCII string + validateTempFilePolicy := func(s string) bool { + return pdf.MemberOf(s, []string{"TEMPNEVER", "TEMPEXTRACT", "TEMPACCESS", "TEMPALWAYS"}) + } + _, err = validateStringEntry(xRefTable, d1, dictName, "TF", OPTIONAL, sinceVersion, validateTempFilePolicy) + + return err +} + +func validateMediaPlayerInfoDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see table 291 + + dictName := "mediaPlayerInfoDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "MediaPlayerInfo" }) + if err != nil { + return err + } + + // PID, required, software identifier dict + d1, err := validateDictEntry(xRefTable, d, dictName, "PID", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + err = validateSoftwareIdentifierDict(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + + // MH, optional, dict + _, err = validateDictEntry(xRefTable, d, dictName, "MH", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // BE, optional, dict + _, err = validateDictEntry(xRefTable, d, dictName, "BE", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateMediaPlayersDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see 13.2.7.2 + + dictName := "mediaPlayersDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "MediaPlayers" }) + if err != nil { + return err + } + + // MU, optional, array of media player info dicts + a, err := validateArrayEntry(xRefTable, d, dictName, "MU", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + if a != nil { + + for _, v := range a { + + if v == nil { + continue + } + + d, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateMediaPlayerInfoDict(xRefTable, d, sinceVersion) + if err != nil { + return err + } + + } + + } + + return nil + +} + +func validateFileSpecOrFormXObjectEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + return validateFileSpecificationOrFormObject(xRefTable, o) +} + +func validateMediaClipDataDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see 13.2.4.2 + + dictName := "mediaClipDataDict" + + // D, required, file specification or stream + err := validateFileSpecOrFormXObjectEntry(xRefTable, d, dictName, "D", REQUIRED, sinceVersion) + if err != nil { + return err + } + + // CT, optional, ASCII string + _, err = validateStringEntry(xRefTable, d, dictName, "CT", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // P, optional, media permissions dict + err = validateMediaPermissionsDict(xRefTable, d, dictName, sinceVersion) + if err != nil { + return err + } + + // Alt, optional, string array + _, err = validateStringArrayEntry(xRefTable, d, dictName, "Alt", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // PL, optional, media players dict + d1, err := validateDictEntry(xRefTable, d, dictName, "PL", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateMediaPlayersDict(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + } + + // MH, optional, dict + d1, err = validateDictEntry(xRefTable, d, dictName, "MH", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + // BU, optional, ASCII string + _, err = validateStringEntry(xRefTable, d1, "", "BU", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + } + + // BE. optional, dict + d1, err = validateDictEntry(xRefTable, d, dictName, "BE", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + // BU, optional, ASCII string + _, err = validateStringEntry(xRefTable, d1, "", "BU", OPTIONAL, sinceVersion, nil) + } + + return err +} + +func validateTimespanDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "timespanDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Timespan" }) + if err != nil { + return err + } + + // S, required, name + _, err = validateNameEntry(xRefTable, d, dictName, "S", REQUIRED, sinceVersion, func(s string) bool { return s == "S" }) + if err != nil { + return err + } + + // V, required, number + _, err = validateNumberEntry(xRefTable, d, dictName, "V", REQUIRED, sinceVersion, nil) + + return err +} + +func validateMediaOffsetDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see 13.2.6.2 + + dictName := "mediaOffsetDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "MediaOffset" }) + if err != nil { + return err + } + + // S, required, name + subType, err := validateNameEntry(xRefTable, d, dictName, "S", REQUIRED, sinceVersion, func(s string) bool { return pdf.MemberOf(s, []string{"T", "F", "M"}) }) + if err != nil { + return err + } + + switch *subType { + + case "T": + d1, err := validateDictEntry(xRefTable, d, dictName, "T", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + err = validateTimespanDict(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + + case "F": + _, err = validateIntegerEntry(xRefTable, d, dictName, "F", REQUIRED, sinceVersion, func(i int) bool { return i >= 0 }) + if err != nil { + return err + } + + case "M": + _, err = validateStringEntry(xRefTable, d, dictName, "M", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + } + + return nil +} + +func validateMediaClipSectionDictMHBE(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "mediaClipSectionMHBE" + + d1, err := validateDictEntry(xRefTable, d, dictName, "B", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateMediaOffsetDict(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + } + + d1, err = validateDictEntry(xRefTable, d, dictName, "E", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateMediaOffsetDict(xRefTable, d1, sinceVersion) + } + + return err +} + +func validateMediaClipSectionDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see 13.2.4.3 + + dictName := "mediaClipSectionDict" + + // D, required, media clip dict + d1, err := validateDictEntry(xRefTable, d, dictName, "D", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + err = validateMediaClipDict(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + + // Alt, optional, string array + _, err = validateStringArrayEntry(xRefTable, d, dictName, "Alt", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // MH, optional, dict + d1, err = validateDictEntry(xRefTable, d, dictName, "MH", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateMediaClipSectionDictMHBE(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + } + + // BE, optional, dict + d1, err = validateDictEntry(xRefTable, d, dictName, "BE", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateMediaClipSectionDictMHBE(xRefTable, d1, sinceVersion) + } + + return err +} + +func validateMediaClipDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see 13.2.4 + + dictName := "mediaClipDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "MediaClip" }) + if err != nil { + return err + } + + // S, required, name + subType, err := validateNameEntry(xRefTable, d, dictName, "S", REQUIRED, sinceVersion, func(s string) bool { return s == "MCD" || s == "MCS" }) + if err != nil { + return err + } + + // N, optional, text string + _, err = validateStringEntry(xRefTable, d, dictName, "N", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + if *subType == "MCD" { + err = validateMediaClipDataDict(xRefTable, d, sinceVersion) + if err != nil { + return err + } + } + + if *subType == "MCS" { + err = validateMediaClipSectionDict(xRefTable, d, sinceVersion) + } + + return err +} + +func validateMediaDurationDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "mediaDurationDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "MediaDuration" }) + if err != nil { + return err + } + + // S, required, name + validate := func(s string) bool { return pdf.MemberOf(s, []string{"I", "F", "T"}) } + s, err := validateNameEntry(xRefTable, d, dictName, "S", REQUIRED, sinceVersion, validate) + if err != nil { + return err + } + + // T, required if S == "T", timespann dict + d1, err := validateDictEntry(xRefTable, d, dictName, "T", *s == "T", sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateTimespanDict(xRefTable, d1, sinceVersion) + } + + return err +} + +func validateMediaPlayParamsMHBEDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "mediaPlayParamsMHBEDict" + + // V, optional, integer + _, err := validateIntegerEntry(xRefTable, d, dictName, "V", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // C, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "C", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // F, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "RT", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // D, optional, media duration dict + d1, err := validateDictEntry(xRefTable, d, dictName, "D", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateMediaDurationDict(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + } + + // A, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "A", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // RC, optional, number + _, err = validateNumberEntry(xRefTable, d, dictName, "RC", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateMediaPlayParamsDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see 13.2.5 + + dictName := "mediaPlayParamsDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "MediaPlayParams" }) + if err != nil { + return err + } + + // PL, optional, media players dict + d1, err := validateDictEntry(xRefTable, d, dictName, "PL", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateMediaPlayersDict(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + } + + // MH, optional, dict + d1, err = validateDictEntry(xRefTable, d, dictName, "MH", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateMediaPlayParamsMHBEDict(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + } + + // BE, optional, dict + d1, err = validateDictEntry(xRefTable, d, dictName, "BE", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateMediaPlayParamsMHBEDict(xRefTable, d1, sinceVersion) + } + + return err +} + +func validateFloatingWindowsParameterDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see table 284 + + dictName := "floatWinParamsDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "FWParams" }) + if err != nil { + return err + } + + // D, required, array of integers + _, err = validateIntegerArrayEntry(xRefTable, d, dictName, "D", REQUIRED, sinceVersion, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + // RT, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "RT", OPTIONAL, sinceVersion, func(i int) bool { return pdf.IntMemberOf(i, []int{0, 1, 2, 3}) }) + if err != nil { + return err + } + + // P, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "P", OPTIONAL, sinceVersion, func(i int) bool { return pdf.IntMemberOf(i, []int{0, 1, 2, 3, 4, 5, 6, 7, 8}) }) + if err != nil { + return err + } + + // O, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "O", OPTIONAL, sinceVersion, func(i int) bool { return pdf.IntMemberOf(i, []int{0, 1, 2}) }) + if err != nil { + return err + } + + // T, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "T", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // UC, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "UC", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // R, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "R", OPTIONAL, sinceVersion, func(i int) bool { return pdf.IntMemberOf(i, []int{0, 1, 2}) }) + if err != nil { + return err + } + + // TT, optional, string array + _, err = validateStringArrayEntry(xRefTable, d, dictName, "TT", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateScreenParametersMHBEDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "screenParmsMHBEDict" + + w := 3 + + // W, optional, integer + i, err := validateIntegerEntry(xRefTable, d, dictName, "W", OPTIONAL, sinceVersion, func(i int) bool { return pdf.IntMemberOf(i, []int{0, 1, 2, 3}) }) + if err != nil { + return err + } + if i != nil { + w = (*i).Value() + } + + // B, optional, array of 3 numbers + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "B", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 3 }) + if err != nil { + return err + } + + // O, optional, number + _, err = validateNumberEntry(xRefTable, d, dictName, "O", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // M, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "M", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // F, required if W == 0, floating windows parameter dict + d1, err := validateDictEntry(xRefTable, d, dictName, "F", w == 0, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateFloatingWindowsParameterDict(xRefTable, d1, sinceVersion) + } + + return err +} + +func validateScreenParametersDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see 13.2. + + dictName := "screenParmsDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "MediaScreenParams" }) + if err != nil { + return err + } + + // MH, optional, dict + d1, err := validateDictEntry(xRefTable, d, dictName, "MH", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateScreenParametersMHBEDict(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + } + + // BE. optional. dict + d1, err = validateDictEntry(xRefTable, d, dictName, "BE", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateScreenParametersMHBEDict(xRefTable, d1, sinceVersion) + } + + return err +} + +func validateMediaRenditionDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // table 271 + + dictName := "mediaRendDict" + + // C, optional, dict + d1, err := validateDictEntry(xRefTable, d, dictName, "C", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateMediaClipDict(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + } + + // P, required if C not present, dict + d1, err = validateDictEntry(xRefTable, d, dictName, "P", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateMediaPlayParamsDict(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + } + + // SP, optional, dict + d1, err = validateDictEntry(xRefTable, d, dictName, "SP", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateScreenParametersDict(xRefTable, d1, sinceVersion) + } + + return err +} + +func validateSelectorRenditionDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // table 272 + + dictName := "selectorRendDict" + + a, err := validateArrayEntry(xRefTable, d, dictName, "R", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + for _, v := range a { + + if v == nil { + continue + } + + d, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateRenditionDict(xRefTable, d, sinceVersion) + if err != nil { + return err + } + + } + + return nil +} + +func validateRenditionDictEntryMH(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, "MH", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + + d2, err := validateDictEntry(xRefTable, d1, "MHDict", "C", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + if d2 != nil { + return validateMediaCriteriaDict(xRefTable, d2, sinceVersion) + } + + } + + return nil +} + +func validateRenditionDictEntryBE(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, sinceVersion pdf.Version) (err error) { + + d1, err := validateDictEntry(xRefTable, d, dictName, "BE", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + + d2, err := validateDictEntry(xRefTable, d1, "BEDict", "C", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + return validateMediaCriteriaDict(xRefTable, d2, sinceVersion) + + } + + return nil +} + +func validateRenditionDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) (err error) { + + dictName := "renditionDict" + + // Type, optional, name + _, err = validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Rendition" }) + if err != nil { + return err + } + + // S, required, name + renditionType, err := validateNameEntry(xRefTable, d, dictName, "S", REQUIRED, sinceVersion, func(s string) bool { return s == "MR" || s == "SR" }) + if err != nil { + return + } + + // N, optional, text string + _, err = validateStringEntry(xRefTable, d, dictName, "N", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // MH, optional, dict + err = validateRenditionDictEntryMH(xRefTable, d, dictName, sinceVersion) + if err != nil { + return err + } + + // BE, optional, dict + err = validateRenditionDictEntryBE(xRefTable, d, dictName, sinceVersion) + if err != nil { + return err + } + + if *renditionType == "MR" { + err = validateMediaRenditionDict(xRefTable, d, sinceVersion) + if err != nil { + return err + } + } + + if *renditionType == "SR" { + err = validateSelectorRenditionDict(xRefTable, d, sinceVersion) + } + + return err +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/nameTree.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/nameTree.go new file mode 100644 index 0000000..3f19f90 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/nameTree.go @@ -0,0 +1,756 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateDestsNameTreeValue(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // Version check + err := xRefTable.ValidateVersion("DestsNameTreeValue", sinceVersion) + if err != nil { + return err + } + + return validateDestination(xRefTable, o) +} + +func validateAPNameTreeValue(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // Version check + err := xRefTable.ValidateVersion("APNameTreeValue", sinceVersion) + if err != nil { + return err + } + + return validateXObjectStreamDict(xRefTable, o) +} + +func validateJavaScriptNameTreeValue(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // Version check + err := xRefTable.ValidateVersion("JavaScriptNameTreeValue", sinceVersion) + if err != nil { + return err + } + + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return err + } + + // Javascript Action: + return validateJavaScriptActionDict(xRefTable, d, "JavaScript") +} + +func validatePagesNameTreeValue(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // see 12.7.6 + + // Version check + err := xRefTable.ValidateVersion("PagesNameTreeValue", sinceVersion) + if err != nil { + return err + } + + // Value is a page dict. + + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return err + } + + if d == nil { + return errors.New("pdfcpu: validatePagesNameTreeValue: value is nil") + } + + _, err = validateNameEntry(xRefTable, d, "pageDict", "Type", REQUIRED, pdf.V10, func(s string) bool { return s == "Page" }) + + return err +} + +func validateTemplatesNameTreeValue(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // see 12.7.6 + + // Version check + err := xRefTable.ValidateVersion("TemplatesNameTreeValue", sinceVersion) + if err != nil { + return err + } + + // Value is a template dict. + + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return err + } + if d == nil { + return errors.New("pdfcpu: validatePagesNameTreeValue: value is nil") + } + + _, err = validateNameEntry(xRefTable, d, "templateDict", "Type", REQUIRED, pdf.V10, func(s string) bool { return s == "Template" }) + + return err +} + +func validateURLAliasDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "urlAliasDict" + + // U, required, ASCII string + _, err := validateStringEntry(xRefTable, d, dictName, "U", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // C, optional, array of strings + _, err = validateStringArrayEntry(xRefTable, d, dictName, "C", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateCommandSettingsDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // see 14.10.5.4 + + dictName := "cmdSettingsDict" + + // G, optional, dict + _, err := validateDictEntry(xRefTable, d, dictName, "G", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // C, optional, dict + _, err = validateDictEntry(xRefTable, d, dictName, "C", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateCaptureCommandDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "captureCommandDict" + + // URL, required, string + _, err := validateStringEntry(xRefTable, d, dictName, "URL", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // L, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "L", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // F, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "F", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // P, optional, string or stream + err = validateStringOrStreamEntry(xRefTable, d, dictName, "P", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // CT, optional, ASCII string + _, err = validateStringEntry(xRefTable, d, dictName, "CT", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // H, optional, string + _, err = validateStringEntry(xRefTable, d, dictName, "H", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // S, optional, command settings dict + d1, err := validateDictEntry(xRefTable, d, dictName, "S", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateCommandSettingsDict(xRefTable, d1) + } + + return err +} + +func validateSourceInfoDictEntryAU(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.StringLiteral, pdf.HexLiteral: + // no further processing + + case pdf.Dict: + err = validateURLAliasDict(xRefTable, o) + if err != nil { + return err + } + + default: + return errors.New("pdfcpu: validateSourceInfoDict: entry \"AU\" must be string or dict") + + } + + return nil +} + +func validateSourceInfoDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "sourceInfoDict" + + // AU, required, ASCII string or dict + err := validateSourceInfoDictEntryAU(xRefTable, d, dictName, "AU", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // E, optional, date + _, err = validateDateEntry(xRefTable, d, dictName, "E", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // S, optional, integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "S", OPTIONAL, pdf.V10, func(i int) bool { return 0 <= i && i <= 2 }) + if err != nil { + return err + } + + // C, optional, indRef of command dict + ir, err := validateIndRefEntry(xRefTable, d, dictName, "C", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + if ir != nil { + + d1, err := xRefTable.DereferenceDict(*ir) + if err != nil { + return err + } + + return validateCaptureCommandDict(xRefTable, d1) + + } + + return nil +} + +func validateEntrySI(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + // see 14.10.5, table 355, source information dictionary + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Dict: + err = validateSourceInfoDict(xRefTable, o) + if err != nil { + return err + } + + case pdf.Array: + + for _, v := range o { + + if v == nil { + continue + } + + d1, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + + err = validateSourceInfoDict(xRefTable, d1) + if err != nil { + return err + } + + } + + } + + return nil +} + +func validateWebCaptureContentSetDict(XRefTable *pdf.XRefTable, d pdf.Dict) error { + + // see 14.10.4 + + dictName := "webCaptureContentSetDict" + + // Type, optional, name + _, err := validateNameEntry(XRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "SpiderContentSet" }) + if err != nil { + return err + } + + // S, required, name + s, err := validateNameEntry(XRefTable, d, dictName, "Type", REQUIRED, pdf.V10, func(s string) bool { return s == "SPS" || s == "SIS" }) + if err != nil { + return err + } + + // ID, required, byte string + _, err = validateStringEntry(XRefTable, d, dictName, "ID", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // O, required, array of indirect references. + _, err = validateIndRefArrayEntry(XRefTable, d, dictName, "O", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // SI, required, source info dict or array of source info dicts + err = validateEntrySI(XRefTable, d, dictName, "SI", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // CT, optional, string + _, err = validateStringEntry(XRefTable, d, dictName, "CT", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // TS, optional, date + _, err = validateDateEntry(XRefTable, d, dictName, "TS", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + // spider page set + if *s == "SPS" { + + // T, optional, string + _, err = validateStringEntry(XRefTable, d, dictName, "T", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // TID, optional, byte string + _, err = validateStringEntry(XRefTable, d, dictName, "TID", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + } + + // spider image set + if *s == "SIS" { + + // R, required, integer or array of integers + err = validateIntegerOrArrayOfIntegerEntry(XRefTable, d, dictName, "R", REQUIRED, pdf.V10) + + } + + return err +} + +func validateIDSNameTreeValue(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // see 14.10.4 + + // Version check + err := xRefTable.ValidateVersion("IDSNameTreeValue", sinceVersion) + if err != nil { + return err + } + + // Value is a web capture content set. + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + return validateWebCaptureContentSetDict(xRefTable, d) +} + +func validateURLSNameTreeValue(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // see 14.10.4 + + // Version check + err := xRefTable.ValidateVersion("URLSNameTreeValue", sinceVersion) + if err != nil { + return err + } + + // Value is a web capture content set. + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + return validateWebCaptureContentSetDict(xRefTable, d) +} + +func validateEmbeddedFilesNameTreeValue(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // see 7.11.4 + + // Value is a file specification for an embedded file stream. + + // Version check + err := xRefTable.ValidateVersion("EmbeddedFilesNameTreeValue", sinceVersion) + if err != nil { + return err + } + + if o == nil { + return nil + } + + _, err = validateFileSpecification(xRefTable, o) + + return err +} + +func validateSlideShowDict(XRefTable *pdf.XRefTable, d pdf.Dict) error { + + // see 13.5, table 297 + + dictName := "slideShowDict" + + // Type, required, name, since V1.4 + _, err := validateNameEntry(XRefTable, d, dictName, "Type", REQUIRED, pdf.V14, func(s string) bool { return s == "SlideShow" }) + if err != nil { + return err + } + + // Subtype, required, name, since V1.4 + _, err = validateNameEntry(XRefTable, d, dictName, "Subtype", REQUIRED, pdf.V14, func(s string) bool { return s == "Embedded" }) + if err != nil { + return err + } + + // Resources, required, name tree, since V1.4 + // Note: This is really an array of (string,indRef) pairs. + _, err = validateArrayEntry(XRefTable, d, dictName, "Resources", REQUIRED, pdf.V14, nil) + if err != nil { + return err + } + + // StartResource, required, byte string, since V1.4 + _, err = validateStringEntry(XRefTable, d, dictName, "StartResource", REQUIRED, pdf.V14, nil) + + return err +} + +func validateAlternatePresentationsNameTreeValue(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // see 13.5 + + // Value is a slide show dict. + + // Version check + err := xRefTable.ValidateVersion("AlternatePresentationsNameTreeValue", sinceVersion) + if err != nil { + return err + } + + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return err + } + + if d != nil { + err = validateSlideShowDict(xRefTable, d) + } + + return err +} + +func validateRenditionsNameTreeValue(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // see 13.2.3 + + // Value is a rendition object. + + // Version check + err := xRefTable.ValidateVersion("RenditionsNameTreeValue", sinceVersion) + if err != nil { + return err + } + + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return err + } + + if d != nil { + err = validateRenditionDict(xRefTable, d, sinceVersion) + } + + return err +} + +func validateIDTreeValue(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // Version check + err := xRefTable.ValidateVersion("IDTreeValue", sinceVersion) + if err != nil { + return err + } + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + dictType := d.Type() + if dictType == nil || *dictType == "StructElem" { + err = validateStructElementDict(xRefTable, d) + if err != nil { + return err + } + } else { + return errors.Errorf("pdfcpu: validateIDTreeValue: invalid dictType %s (should be \"StructElem\")\n", *dictType) + } + + return nil +} + +func validateNameTreeValue(name string, xRefTable *pdf.XRefTable, o pdf.Object) (err error) { + + // TODO + // The values associated with the keys may be objects of any type. + // Stream objects shall be specified by indirect object references. + // Dictionary, array, and string objects should be specified by indirect object references. + // Other PDF objects (nulls, numbers, booleans, and names) should be specified as direct objects. + + for k, v := range map[string]struct { + validate func(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error + sinceVersion pdf.Version + }{ + "Dests": {validateDestsNameTreeValue, pdf.V12}, + "AP": {validateAPNameTreeValue, pdf.V13}, + "JavaScript": {validateJavaScriptNameTreeValue, pdf.V13}, + "Pages": {validatePagesNameTreeValue, pdf.V13}, + "Templates": {validateTemplatesNameTreeValue, pdf.V13}, + "IDS": {validateIDSNameTreeValue, pdf.V13}, + "URLS": {validateURLSNameTreeValue, pdf.V13}, + "EmbeddedFiles": {validateEmbeddedFilesNameTreeValue, pdf.V14}, + "AlternatePresentations": {validateAlternatePresentationsNameTreeValue, pdf.V14}, + "Renditions": {validateRenditionsNameTreeValue, pdf.V15}, + "IDTree": {validateIDTreeValue, pdf.V13}, + } { + if name == k { + return v.validate(xRefTable, o, v.sinceVersion) + } + } + + return errors.Errorf("pdfcpu: validateNameTreeDictNamesEntry: unknown dict name: %s", name) +} + +func validateNameTreeDictNamesEntry(xRefTable *pdf.XRefTable, d pdf.Dict, name string, node *pdf.Node) (firstKey, lastKey string, err error) { + + // Names: array of the form [key1 value1 key2 value2 ... key n value n] + o, found := d.Find("Names") + if !found { + return "", "", errors.Errorf("pdfcpu: validateNameTreeDictNamesEntry: missing \"Kids\" or \"Names\" entry.") + } + + a, err := xRefTable.DereferenceArray(o) + if err != nil { + return "", "", err + } + if a == nil { + return "", "", errors.Errorf("pdfcpu: validateNameTreeDictNamesEntry: missing \"Names\" array.") + } + + // arr length needs to be even because of contained key value pairs. + if len(a)%2 == 1 { + return "", "", errors.Errorf("pdfcpu: validateNameTreeDictNamesEntry: Names array entry length needs to be even, length=%d\n", len(a)) + } + + var key string + for i, o := range a { + + if i%2 == 0 { + + o, err = xRefTable.Dereference(o) + if err != nil { + return "", "", err + } + + s, ok := o.(pdf.StringLiteral) + if !ok { + s, ok := o.(pdf.HexLiteral) + if !ok { + return "", "", errors.Errorf("pdfcpu: validateNameTreeDictNamesEntry: corrupt key <%v>\n", o) + } + key = s.Value() + } else { + key = s.Value() + } + + if firstKey == "" { + firstKey = key + } + + lastKey = key + + continue + } + + err = validateNameTreeValue(name, xRefTable, o) + if err != nil { + return "", "", err + } + + node.AddToLeaf(key, o) + } + + return firstKey, lastKey, nil +} + +func validateNameTreeDictLimitsEntry(xRefTable *pdf.XRefTable, d pdf.Dict, firstKey, lastKey string) error { + + a, err := validateStringArrayEntry(xRefTable, d, "nameTreeDict", "Limits", REQUIRED, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + //fmt.Printf("validateNameTreeDictLimitsEntry: firstKey=%s lastKey=%s limits:%v\n", firstKey, lastKey, a) + + var fkv, lkv string + + fk, ok := a[0].(pdf.StringLiteral) + if !ok { + fk, _ := a[0].(pdf.HexLiteral) + //bb, _ := fk.Bytes() + //fmt.Printf("fk: %v %s\n", bb, string(bb)) + fkv = fk.Value() + } else { + fkv = fk.Value() + } + + lk, ok := a[1].(pdf.StringLiteral) + if !ok { + lk, _ := a[1].(pdf.HexLiteral) + //bb, _ := lk.Bytes() + //fmt.Printf("lk: %v %s\n", bb, string(bb)) + lkv = lk.Value() + } else { + lkv = lk.Value() + } + + if firstKey < fkv || lastKey > lkv { + return errors.Errorf("pdfcpu: validateNameTreeDictLimitsEntry: leaf node corrupted (firstKey: %s vs %s) (lastKey: %s vs %s)\n", firstKey, fkv, lastKey, lkv) + } + + return nil +} + +func validateNameTree(xRefTable *pdf.XRefTable, name string, d pdf.Dict, root bool) (string, string, *pdf.Node, error) { + + // see 7.7.4 + + // A node has "Kids" or "Names" entry. + + //fmt.Printf("validateNameTree %s\n", name) + + node := &pdf.Node{D: d} + var kmin, kmax string + var err error + + // Kids: array of indirect references to the immediate children of this node. + // if Kids present then recurse + if o, found := d.Find("Kids"); found { + + // Intermediate node + + a, err := xRefTable.DereferenceArray(o) + if err != nil { + return "", "", nil, err + } + + if a == nil { + return "", "", nil, errors.New("pdfcpu: validateNameTree: missing \"Kids\" array") + } + + for _, o := range a { + + kid, ok := o.(pdf.IndirectRef) + if !ok { + return "", "", nil, errors.New("pdfcpu: validateNameTree: corrupt kid, should be indirect reference") + } + + d, err := xRefTable.DereferenceDict(kid) + if err != nil { + return "", "", nil, err + } + + var kminKid string + var kidNode *pdf.Node + kminKid, kmax, kidNode, err = validateNameTree(xRefTable, name, d, false) + if err != nil { + return "", "", nil, err + } + if kmin == "" { + kmin = kminKid + } + + node.Kids = append(node.Kids, kidNode) + } + + } else { + + // Leaf node + kmin, kmax, err = validateNameTreeDictNamesEntry(xRefTable, d, name, node) + if err != nil { + return "", "", nil, err + } + } + + if !root { + + // Verify calculated key range. + err = validateNameTreeDictLimitsEntry(xRefTable, d, kmin, kmax) + if err != nil { + return "", "", nil, err + } + } + + // We track limits for all nodes internally. + node.Kmin = kmin + node.Kmax = kmax + + return kmin, kmax, node, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/numberTree.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/numberTree.go new file mode 100644 index 0000000..4453ae3 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/numberTree.go @@ -0,0 +1,207 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validatePageLabelDict(xRefTable *pdf.XRefTable, o pdf.Object) error { + + // see 12.4.2 Page Labels + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + dictName := "pageLabelDict" + + // Type, optional, name + _, err = validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "PageLabel" }) + if err != nil { + return err + } + + // Optional name entry S + // The numbering style that shall be used for the numeric portion of each page label. + validate := func(s string) bool { return pdf.MemberOf(s, []string{"D", "R", "r", "A", "a"}) } + _, err = validateNameEntry(xRefTable, d, dictName, "S", OPTIONAL, pdf.V10, validate) + if err != nil { + return err + } + + // Optional string entry P + // Label prefix for page labels in this range. + _, err = validateStringEntry(xRefTable, d, dictName, "P", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Optional integer entry St + // The value of the numeric portion for the first page label in the range. + _, err = validateIntegerEntry(xRefTable, d, dictName, "St", OPTIONAL, pdf.V10, func(i int) bool { return i >= 1 }) + + return err +} + +func validateNumberTreeDictNumsEntry(xRefTable *pdf.XRefTable, d pdf.Dict, name string) (firstKey, lastKey int, err error) { + + // Nums: array of the form [key1 value1 key2 value2 ... key n value n] + o, found := d.Find("Nums") + if !found { + return 0, 0, errors.New("pdfcpu: validateNumberTreeDictNumsEntry: missing \"Kids\" or \"Nums\" entry") + } + + a, err := xRefTable.DereferenceArray(o) + if err != nil { + return 0, 0, err + } + if a == nil { + return 0, 0, errors.New("pdfcpu: validateNumberTreeDictNumsEntry: missing \"Nums\" array") + } + + // arr length needs to be even because of contained key value pairs. + if len(a)%2 == 1 { + return 0, 0, errors.Errorf("pdfcpu: validateNumberTreeDictNumsEntry: Nums array entry length needs to be even, length=%d\n", len(a)) + } + + // every other entry is a value + // value = indRef to an array of indRefs of structElemDicts + // or + // value = indRef of structElementDict. + + for i, o := range a { + + if i%2 == 0 { + + o, err = xRefTable.Dereference(o) + if err != nil { + return 0, 0, err + } + + i, ok := o.(pdf.Integer) + if !ok { + return 0, 0, errors.Errorf("pdfcpu: validateNumberTreeDictNumsEntry: corrupt key <%v>\n", o) + } + + if firstKey == 0 { + firstKey = i.Value() + } + + lastKey = i.Value() + + continue + } + + switch name { + + case "PageLabel": + err = validatePageLabelDict(xRefTable, o) + if err != nil { + return 0, 0, err + } + + case "StructTree": + err = validateStructTreeRootDictEntryK(xRefTable, o) + if err != nil { + return 0, 0, err + } + } + + } + + return firstKey, lastKey, nil +} + +func validateNumberTreeDictLimitsEntry(xRefTable *pdf.XRefTable, d pdf.Dict, firstKey, lastKey int) error { + + a, err := validateIntegerArrayEntry(xRefTable, d, "numberTreeDict", "Limits", REQUIRED, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + fk, _ := a[0].(pdf.Integer) + lk, _ := a[1].(pdf.Integer) + + if firstKey < fk.Value() || lastKey > lk.Value() { + return errors.Errorf("pdfcpu: validateNumberTreeDictLimitsEntry: leaf node corrupted: firstKey(%d vs. %d) lastKey(%d vs. %d)\n", firstKey, fk.Value(), lastKey, lk.Value()) + } + + return nil +} + +func validateNumberTree(xRefTable *pdf.XRefTable, name string, ir pdf.IndirectRef, root bool) (firstKey, lastKey int, err error) { + + // A node has "Kids" or "Nums" entry. + + d, err := xRefTable.DereferenceDict(ir) + if err != nil || d == nil { + return 0, 0, err + } + + // Kids: array of indirect references to the immediate children of this node. + // if Kids present then recurse + if o, found := d.Find("Kids"); found { + + a, err := xRefTable.DereferenceArray(o) + if err != nil { + return 0, 0, err + } + if a == nil { + return 0, 0, errors.New("pdfcpu: validateNumberTree: missing \"Kids\" array") + } + + for _, o := range a { + + kid, ok := o.(pdf.IndirectRef) + if !ok { + return 0, 0, errors.New("pdfcpu: validateNumberTree: corrupt kid, should be indirect reference") + } + + var fk int + fk, lastKey, err = validateNumberTree(xRefTable, name, kid, false) + if err != nil { + return 0, 0, err + } + if firstKey == 0 { + firstKey = fk + } + } + + } else { + + // Leaf node + firstKey, lastKey, err = validateNumberTreeDictNumsEntry(xRefTable, d, name) + if err != nil { + return 0, 0, err + } + } + + if !root { + + // Verify calculated key range. + err = validateNumberTreeDictLimitsEntry(xRefTable, d, firstKey, lastKey) + if err != nil { + return 0, 0, err + } + + } + + return firstKey, lastKey, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/objects.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/objects.go new file mode 100644 index 0000000..35ca3e8 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/objects.go @@ -0,0 +1,1601 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + "fmt" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/log" + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +const ( + + // REQUIRED is used for required dict entries. + REQUIRED = true + + // OPTIONAL is used for optional dict entries. + OPTIONAL = false +) + +func validateEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) (pdf.Object, error) { + + o, found := d.Find(entryName) + if !found || o == nil { + if required { + return nil, errors.Errorf("dict=%s required entry=%s missing.", dictName, entryName) + } + return nil, nil + } + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + + if o == nil { + if required { + return nil, errors.Errorf("dict=%s required entry=%s missing.", dictName, entryName) + } + return nil, nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return nil, err + } + + return o, nil +} + +func validateArrayEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(pdf.Array) bool) (pdf.Array, error) { + + log.Validate.Printf("validateArrayEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return nil, err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return nil, err + } + if o == nil { + if required { + return nil, errors.Errorf("validateArrayEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateArrayEntry end: optional entry %s is nil\n", entryName) + return nil, nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return nil, err + } + + a, ok := o.(pdf.Array) + if !ok { + return nil, errors.Errorf("validateArrayEntry: dict=%s entry=%s invalid type %T", dictName, entryName, o) + } + + // Validation + if validate != nil && !validate(a) { + return nil, errors.Errorf("validateArrayEntry: dict=%s entry=%s invalid dict entry", dictName, entryName) + } + + log.Validate.Printf("validateArrayEntry end: entry=%s\n", entryName) + + return a, nil +} + +func validateBooleanEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(bool) bool) (*pdf.Boolean, error) { + + log.Validate.Printf("validateBooleanEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return nil, err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return nil, err + } + if o == nil { + if required { + return nil, errors.Errorf("validateBooleanEntry: dict=%s required entry=%s missing", dictName, entryName) + } + log.Validate.Printf("validateBooleanEntry end: entry %s is nil\n", entryName) + return nil, nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return nil, err + } + + b, ok := o.(pdf.Boolean) + if !ok { + return nil, errors.Errorf("validateBooleanEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + // Validation + if validate != nil && !validate(b.Value()) { + return nil, errors.Errorf("validateBooleanEntry: dict=%s entry=%s invalid name dict entry", dictName, entryName) + } + + log.Validate.Printf("validateBooleanEntry end: entry=%s\n", entryName) + + return &b, nil +} + +func validateBooleanArrayEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(pdf.Array) bool) (pdf.Array, error) { + + log.Validate.Printf("validateBooleanArrayEntry begin: entry=%s\n", entryName) + + a, err := validateArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, validate) + if err != nil || a == nil { + return nil, err + } + + for i, o := range a { + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + if o == nil { + continue + } + + _, ok := o.(pdf.Boolean) + if !ok { + return nil, errors.Errorf("validateBooleanArrayEntry: dict=%s entry=%s invalid type at index %d\n", dictName, entryName, i) + } + + } + + log.Validate.Printf("validateBooleanArrayEntry end: entry=%s\n", entryName) + + return a, nil +} + +func validateDateObject(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) (string, error) { + sl, err := xRefTable.DereferenceStringLiteral(o, sinceVersion, nil) + if err != nil { + return "", err + } + s := sl.Value() + if s == "" { + return s, nil + } + + if _, ok := pdf.DateTime(s); !ok { + return "", errors.Errorf("pdfcpu: validateDateObject: <%s> invalid date", s) + } + + return s, nil +} + +func validateDateEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) (*time.Time, error) { + + log.Validate.Printf("validateDateEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return nil, err + } + + s, err := xRefTable.DereferenceStringOrHexLiteral(o, sinceVersion, nil) + if err != nil { + return nil, err + } + if s == "" { + if required { + return nil, errors.Errorf("validateDateEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateDateEntry end: optional entry %s is nil\n", entryName) + return nil, nil + } + + time, ok := pdf.DateTime(s) + if !ok { + return nil, errors.Errorf("pdfcpu: validateDateEntry: <%s> invalid date", s) + } + + log.Validate.Printf("validateDateEntry end: entry=%s\n", entryName) + + return &time, nil +} + +func validateDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(pdf.Dict) bool) (pdf.Dict, error) { + + log.Validate.Printf("validateDictEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return nil, err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return nil, err + } + if o == nil { + if required { + return nil, errors.Errorf("validateDictEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateDictEntry end: optional entry %s is nil\n", entryName) + return nil, nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return nil, err + } + + d, ok := o.(pdf.Dict) + if !ok { + return nil, errors.Errorf("validateDictEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + // Validation + if validate != nil && !validate(d) { + return nil, errors.Errorf("validateDictEntry: dict=%s entry=%s invalid dict entry", dictName, entryName) + } + + log.Validate.Printf("validateDictEntry end: entry=%s\n", entryName) + + return d, nil +} + +func validateFloat(xRefTable *pdf.XRefTable, o pdf.Object, validate func(float64) bool) (*pdf.Float, error) { + + log.Validate.Println("validateFloat begin") + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + if o == nil { + return nil, errors.New("pdfcpu: validateFloat: missing object") + } + + f, ok := o.(pdf.Float) + if !ok { + return nil, errors.New("pdfcpu: validateFloat: invalid type") + } + + // Validation + if validate != nil && !validate(f.Value()) { + return nil, errors.Errorf("pdfcpu: validateFloat: invalid float: %s\n", f) + } + + log.Validate.Println("validateFloat end") + + return &f, nil +} + +func validateFloatEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(float64) bool) (*pdf.Float, error) { + + log.Validate.Printf("validateFloatEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return nil, err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return nil, err + } + if o == nil { + if required { + return nil, errors.Errorf("pdfcpu: validateFloatEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateFloatEntry end: optional entry %s is nil\n", entryName) + return nil, nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return nil, err + } + + f, ok := o.(pdf.Float) + if !ok { + return nil, errors.Errorf("pdfcpu: validateFloatEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + // Validation + if validate != nil && !validate(f.Value()) { + return nil, errors.Errorf("pdfcpu: validateFloatEntry: dict=%s entry=%s invalid dict entry", dictName, entryName) + } + + log.Validate.Printf("validateFloatEntry end: entry=%s\n", entryName) + + return &f, nil +} + +func validateFunctionEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + log.Validate.Printf("validateFunctionEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return err + } + + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return err + } + + err = validateFunction(xRefTable, o) + if err != nil { + return err + } + + log.Validate.Printf("validateFunctionEntry end: entry=%s\n", entryName) + + return nil +} + +func validateFunctionArrayEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(pdf.Array) bool) (pdf.Array, error) { + + log.Validate.Printf("validateFunctionArrayEntry begin: entry=%s\n", entryName) + + a, err := validateArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, validate) + if err != nil || a == nil { + return nil, err + } + + for _, o := range a { + err = validateFunction(xRefTable, o) + if err != nil { + return nil, err + } + } + + log.Validate.Printf("validateFunctionArrayEntry end: entry=%s\n", entryName) + + return a, nil +} + +func validateFunctionOrArrayOfFunctionsEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + log.Validate.Printf("validateFunctionOrArrayOfFunctionsEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return err + } + if o == nil { + if required { + return errors.Errorf("pdfcpu: validateFunctionOrArrayOfFunctionsEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateFunctionOrArrayOfFunctionsEntry end: optional entry %s is nil\n", entryName) + return nil + } + + switch o := o.(type) { + + case pdf.Array: + + for _, o := range o { + + if o == nil { + continue + } + + err = validateFunction(xRefTable, o) + if err != nil { + return err + } + + } + + default: + err = validateFunction(xRefTable, o) + if err != nil { + return err + } + + } + + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return err + } + + log.Validate.Printf("validateFunctionOrArrayOfFunctionsEntry end: entry=%s\n", entryName) + + return nil +} + +func validateIndRefEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) (*pdf.IndirectRef, error) { + + log.Validate.Printf("validateIndRefEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return nil, err + } + + ir, ok := o.(pdf.IndirectRef) + if !ok { + return nil, errors.Errorf("pdfcpu: validateIndRefEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return nil, err + } + + log.Validate.Printf("validateIndRefEntry end: entry=%s\n", entryName) + + return &ir, nil +} + +func validateIndRefArrayEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(pdf.Array) bool) (pdf.Array, error) { + + log.Validate.Printf("validateIndRefArrayEntry begin: entry=%s\n", entryName) + + a, err := validateArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, validate) + if err != nil || a == nil { + return nil, err + } + + for i, o := range a { + _, ok := o.(pdf.IndirectRef) + if !ok { + return nil, errors.Errorf("pdfcpu: validateIndRefArrayEntry: invalid type at index %d\n", i) + } + } + + log.Validate.Printf("validateIndRefArrayEntry end: entry=%s \n", entryName) + + return a, nil +} + +func validateInteger(xRefTable *pdf.XRefTable, o pdf.Object, validate func(int) bool) (*pdf.Integer, error) { + + log.Validate.Println("validateInteger begin") + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + + if o == nil { + return nil, errors.New("pdfcpu: validateInteger: missing object") + } + + i, ok := o.(pdf.Integer) + if !ok { + return nil, errors.New("pdfcpu: validateInteger: invalid type") + } + + // Validation + if validate != nil && !validate(i.Value()) { + return nil, errors.Errorf("pdfcpu: validateInteger: invalid integer: %s\n", i) + } + + log.Validate.Println("validateInteger end") + + return &i, nil +} + +func validateIntegerEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(int) bool) (*pdf.Integer, error) { + + log.Validate.Printf("validateIntegerEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return nil, err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return nil, err + } + if o == nil { + if required { + return nil, errors.Errorf("pdfcpu: validateIntegerEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateIntegerEntry end: optional entry %s is nil\n", entryName) + return nil, nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return nil, err + } + + i, ok := o.(pdf.Integer) + if !ok { + return nil, errors.Errorf("pdfcpu: validateIntegerEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + // Validation + if validate != nil && !validate(i.Value()) { + return nil, errors.Errorf("pdfcpu: validateIntegerEntry: dict=%s entry=%s invalid dict entry", dictName, entryName) + } + + log.Validate.Printf("validateIntegerEntry end: entry=%s\n", entryName) + + return &i, nil +} + +func validateIntegerArray(xRefTable *pdf.XRefTable, o pdf.Object) (pdf.Array, error) { + + log.Validate.Println("validateIntegerArray begin") + + a, err := xRefTable.DereferenceArray(o) + if err != nil || a == nil { + return nil, err + } + + for i, o := range a { + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + + if o == nil { + continue + } + + switch o.(type) { + + case pdf.Integer: + // no further processing. + + default: + return nil, errors.Errorf("pdfcpu: validateIntegerArray: invalid type at index %d\n", i) + } + + } + + log.Validate.Println("validateIntegerArray end") + + return a, nil +} + +func validateIntegerArrayEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(pdf.Array) bool) (pdf.Array, error) { + + log.Validate.Printf("validateIntegerArrayEntry begin: entry=%s\n", entryName) + + a, err := validateArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, validate) + if err != nil || a == nil { + return nil, err + } + + for i, o := range a { + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + + if o == nil { + continue + } + + _, ok := o.(pdf.Integer) + if !ok { + return nil, errors.Errorf("pdfcpu: validateIntegerArrayEntry: dict=%s entry=%s invalid type at index %d\n", dictName, entryName, i) + } + + } + + log.Validate.Printf("validateIntegerArrayEntry end: entry=%s\n", entryName) + + return a, nil +} + +func validateName(xRefTable *pdf.XRefTable, o pdf.Object, validate func(string) bool) (*pdf.Name, error) { + + log.Validate.Println("validateName begin") + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + if o == nil { + return nil, errors.New("pdfcpu: validateName: missing object") + } + + name, ok := o.(pdf.Name) + if !ok { + return nil, errors.New("pdfcpu: validateName: invalid type") + } + + // Validation + if validate != nil && !validate(name.Value()) { + return nil, errors.Errorf("pdfcpu: validateName: invalid name: %s\n", name) + } + + log.Validate.Println("validateName end") + + return &name, nil +} + +func validateNameEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(string) bool) (*pdf.Name, error) { + + log.Validate.Printf("validateNameEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return nil, err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return nil, err + } + if o == nil { + if required { + return nil, errors.Errorf("pdfcpu: validateNameEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateNameEntry end: optional entry %s is nil\n", entryName) + return nil, nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return nil, err + } + + name, ok := o.(pdf.Name) + if !ok { + return nil, errors.Errorf("pdfcpu: validateNameEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + // Validation + v := name.Value() + if validate != nil && (required || len(v) > 0) && !validate(v) { + return nil, errors.Errorf("pdfcpu: validateNameEntry: dict=%s entry=%s invalid dict entry: %s", dictName, entryName, name.Value()) + } + + log.Validate.Printf("validateNameEntry end: entry=%s\n", entryName) + + return &name, nil +} + +func validateNameArray(xRefTable *pdf.XRefTable, o pdf.Object) (pdf.Array, error) { + + log.Validate.Println("validateNameArray begin") + + a, err := xRefTable.DereferenceArray(o) + if err != nil || a == nil { + return nil, err + } + + for i, o := range a { + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + + if o == nil { + continue + } + + _, ok := o.(pdf.Name) + if !ok { + return nil, errors.Errorf("pdfcpu: validateNameArray: invalid type at index %d\n", i) + } + + } + + log.Validate.Println("validateNameArray end") + + return a, nil +} + +func validateNameArrayEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(a pdf.Array) bool) (pdf.Array, error) { + + log.Validate.Printf("validateNameArrayEntry begin: entry=%s\n", entryName) + + a, err := validateArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, validate) + if err != nil || a == nil { + return nil, err + } + + for i, o := range a { + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + + if o == nil { + continue + } + + _, ok := o.(pdf.Name) + if !ok { + return nil, errors.Errorf("pdfcpu: validateNameArrayEntry: dict=%s entry=%s invalid type at index %d\n", dictName, entryName, i) + } + + } + + log.Validate.Printf("validateNameArrayEntry end: entry=%s\n", entryName) + + return a, nil +} + +func validateNumber(xRefTable *pdf.XRefTable, o pdf.Object) (pdf.Object, error) { + + log.Validate.Println("validateNumber begin") + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + if o == nil { + return nil, errors.New("pdfcpu: validateNumber: missing object") + } + + switch o.(type) { + + case pdf.Integer: + // no further processing. + + case pdf.Float: + // no further processing. + + default: + return nil, errors.New("pdfcpu: validateNumber: invalid type") + + } + + log.Validate.Println("validateNumber end ") + + return o, nil +} + +func validateNumberEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(f float64) bool) (pdf.Object, error) { + + log.Validate.Printf("validateNumberEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return nil, err + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return nil, err + } + + o, err = validateNumber(xRefTable, o) + if err != nil { + return nil, err + } + + var f float64 + + // Validation + switch o := o.(type) { + + case pdf.Integer: + f = float64(o.Value()) + + case pdf.Float: + f = o.Value() + } + + if validate != nil && !validate(f) { + return nil, errors.Errorf("pdfcpu: validateFloatEntry: dict=%s entry=%s invalid dict entry", dictName, entryName) + } + + log.Validate.Printf("validateNumberEntry end: entry=%s\n", entryName) + + return o, nil +} + +func validateNumberArray(xRefTable *pdf.XRefTable, o pdf.Object) (pdf.Array, error) { + + log.Validate.Println("validateNumberArray begin") + + a, err := xRefTable.DereferenceArray(o) + if err != nil || a == nil { + return nil, err + } + + for i, o := range a { + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + + if o == nil { + continue + } + + switch o.(type) { + + case pdf.Integer: + // no further processing. + + case pdf.Float: + // no further processing. + + default: + return nil, errors.Errorf("pdfcpu: validateNumberArray: invalid type at index %d\n", i) + } + + } + + log.Validate.Println("validateNumberArray end") + + return a, err +} + +func validateNumberArrayEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(pdf.Array) bool) (pdf.Array, error) { + + log.Validate.Printf("validateNumberArrayEntry begin: entry=%s\n", entryName) + + a, err := validateArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, validate) + if err != nil || a == nil { + return nil, err + } + + for i, o := range a { + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + + if o == nil { + continue + } + + switch o.(type) { + + case pdf.Integer: + // no further processing. + + case pdf.Float: + // no further processing. + + default: + return nil, errors.Errorf("pdfcpu: validateNumberArrayEntry: invalid type at index %d\n", i) + } + + } + + log.Validate.Printf("validateNumberArrayEntry end: entry=%s\n", entryName) + + return a, nil +} + +func validateRectangleEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(pdf.Array) bool) (pdf.Array, error) { + + log.Validate.Printf("validateRectangleEntry begin: entry=%s\n", entryName) + + a, err := validateNumberArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, func(a pdf.Array) bool { return len(a) == 4 }) + if err != nil || a == nil { + return nil, err + } + + if validate != nil && !validate(a) { + return nil, errors.Errorf("pdfcpu: validateRectangleEntry: dict=%s entry=%s invalid rectangle entry", dictName, entryName) + } + + log.Validate.Printf("validateRectangleEntry end: entry=%s\n", entryName) + + return a, nil +} + +func validateStreamDict(xRefTable *pdf.XRefTable, o pdf.Object) (*pdf.StreamDict, error) { + + log.Validate.Println("validateStreamDict begin") + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + if o == nil { + return nil, errors.New("pdfcpu: validateStreamDict: missing object") + } + + sd, ok := o.(pdf.StreamDict) + if !ok { + return nil, errors.New("pdfcpu: validateStreamDict: invalid type") + } + + log.Validate.Println("validateStreamDict endobj") + + return &sd, nil +} + +func validateStreamDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(pdf.StreamDict) bool) (*pdf.StreamDict, error) { + + log.Validate.Printf("validateStreamDictEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return nil, err + } + + sd, valid, err := xRefTable.DereferenceStreamDict(o) + if valid { + return nil, nil + } + if err != nil || sd == nil { + return nil, err + } + + // o, err = xRefTable.Dereference(o) + // if err != nil { + // return nil, err + // } + if sd == nil { + if required { + return nil, errors.Errorf("pdfcpu: validateStreamDictEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateStreamDictEntry end: optional entry %s is nil\n", entryName) + return nil, nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return nil, err + } + + // sd, ok := o.(pdf.StreamDict) + // if !ok { + // return nil, errors.Errorf("pdfcpu: validateStreamDictEntry: dict=%s entry=%s invalid type", dictName, entryName) + // } + + // Validation + if validate != nil && !validate(*sd) { + return nil, errors.Errorf("pdfcpu: validateStreamDictEntry: dict=%s entry=%s invalid dict entry", dictName, entryName) + } + + log.Validate.Printf("validateStreamDictEntry end: entry=%s\n", entryName) + + return sd, nil +} + +func validateString(xRefTable *pdf.XRefTable, o pdf.Object, validate func(string) bool) (string, error) { + + //log.Validate.Println("validateString begin") + + o, err := xRefTable.Dereference(o) + if err != nil { + return "", err + } + if o == nil { + return "", errors.New("pdfcpu: validateString: missing object") + } + + var s string + + switch o := o.(type) { + + case pdf.StringLiteral: + s, err = pdf.StringLiteralToString(o.Value()) + + case pdf.HexLiteral: + s, err = pdf.HexLiteralToString(o.Value()) + + default: + err = errors.New("pdfcpu: validateString: invalid type") + } + + if err != nil { + return s, err + } + + // Validation + if validate != nil && !validate(s) { + return "", errors.Errorf("pdfcpu: validateString: %s invalid", s) + } + + //log.Validate.Println("validateString end") + + return s, nil +} + +func validateStringEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(string) bool) (*string, error) { + + log.Validate.Printf("validateStringEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return nil, err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return nil, err + } + if o == nil { + if required { + return nil, errors.Errorf("pdfcpu: validateStringEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateStringEntry end: optional entry %s is nil\n", entryName) + return nil, nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return nil, err + } + + var s string + + switch o := o.(type) { + + case pdf.StringLiteral: + s, err = pdf.StringLiteralToString(o.Value()) + + case pdf.HexLiteral: + s, err = pdf.HexLiteralToString(o.Value()) + + default: + err = errors.Errorf("pdfcpu: validateStringEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + if err != nil { + return nil, err + } + + // Validation + if validate != nil && (required || len(s) > 0) && !validate(s) { + return nil, errors.Errorf("pdfcpu: validateStringEntry: dict=%s entry=%s invalid dict entry", dictName, entryName) + } + + log.Validate.Printf("validateStringEntry end: entry=%s\n", entryName) + + return &s, nil +} + +func validateStringArrayEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(pdf.Array) bool) (pdf.Array, error) { + + log.Validate.Printf("validateStringArrayEntry begin: entry=%s\n", entryName) + + a, err := validateArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, validate) + if err != nil || a == nil { + return nil, err + } + + for i, o := range a { + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + + if o == nil { + continue + } + + switch o.(type) { + + case pdf.StringLiteral: + // no further processing. + + case pdf.HexLiteral: + // no further processing + + default: + return nil, errors.Errorf("pdfcpu: validateStringArrayEntry: invalid type at index %d\n", i) + } + + } + + log.Validate.Printf("validateStringArrayEntry end: entry=%s\n", entryName) + + return a, nil +} + +func validateArrayArrayEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version, validate func(pdf.Array) bool) (pdf.Array, error) { + + log.Validate.Printf("validateArrayArrayEntry begin: entry=%s\n", entryName) + + a, err := validateArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, validate) + if err != nil || a == nil { + return nil, err + } + + for i, o := range a { + + o, err := xRefTable.Dereference(o) + if err != nil { + return nil, err + } + + if o == nil { + continue + } + + switch o.(type) { + + case pdf.Array: + // no further processing. + + default: + return nil, errors.Errorf("pdfcpu: validateArrayArrayEntry: invalid type at index %d\n", i) + } + + } + + log.Validate.Printf("validateArrayArrayEntry end: entry=%s\n", entryName) + + return a, nil +} + +func validateStringOrStreamEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + log.Validate.Printf("validateStringOrStreamEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return err + } + if o == nil { + if required { + return errors.Errorf("pdfcpu: validateStringOrStreamEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateStringOrStreamEntry end: optional entry %s is nil\n", entryName) + return nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return err + } + + switch o.(type) { + + case pdf.StringLiteral, pdf.HexLiteral, pdf.StreamDict: + // no further processing + + default: + return errors.Errorf("pdfcpu: validateStringOrStreamEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + log.Validate.Printf("validateStringOrStreamEntry end: entry=%s\n", entryName) + + return nil +} + +func validateNameOrStringEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + log.Validate.Printf("validateNameOrStringEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return err + } + if o == nil { + if required { + return errors.Errorf("pdfcpu: validateNameOrStringEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateNameOrStringEntry end: optional entry %s is nil\n", entryName) + return nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return err + } + + switch o.(type) { + + case pdf.StringLiteral, pdf.Name: + // no further processing + + default: + return errors.Errorf("pdfcpu: validateNameOrStringEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + log.Validate.Printf("validateNameOrStringEntry end: entry=%s\n", entryName) + + return nil +} + +func validateIntOrStringEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + log.Validate.Printf("validateIntOrStringEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return err + } + if o == nil { + if required { + return errors.Errorf("pdfcpu: validateIntOrStringEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateIntOrStringEntry end: optional entry %s is nil\n", entryName) + return nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return err + } + + switch o.(type) { + + case pdf.StringLiteral, pdf.HexLiteral, pdf.Integer: + // no further processing + + default: + return errors.Errorf("pdfcpu: validateIntOrStringEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + log.Validate.Printf("validateIntOrStringEntry end: entry=%s\n", entryName) + + return nil +} + +func validateIntOrDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + log.Validate.Printf("validateIntOrDictEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return err + } + if o == nil { + if required { + return errors.Errorf("pdfcpu: validateIntOrDictEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateIntOrDictEntry end: optional entry %s is nil\n", entryName) + return nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return err + } + + switch o.(type) { + + case pdf.Integer, pdf.Dict: + // no further processing + + default: + return errors.Errorf("pdfcpu: validateIntOrDictEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + log.Validate.Printf("validateIntOrDictEntry end: entry=%s\n", entryName) + + return nil +} + +func validateBooleanOrStreamEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + log.Validate.Printf("validateBooleanOrStreamEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return err + } + if o == nil { + if required { + return errors.Errorf("pdfcpu: validateBooleanOrStreamEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateBooleanOrStreamEntry end: optional entry %s is nil\n", entryName) + return nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return err + } + + switch o.(type) { + + case pdf.Boolean, pdf.StreamDict: + // no further processing + + default: + return errors.Errorf("pdfcpu: validateBooleanOrStreamEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + log.Validate.Printf("validateBooleanOrStreamEntry end: entry=%s\n", entryName) + + return nil +} + +func validateStreamDictOrDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + log.Validate.Printf("validateStreamDictOrDictEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return err + } + if o == nil { + if required { + return errors.Errorf("pdfcpu: validateStreamDictOrDictEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateStreamDictOrDictEntry end: optional entry %s is nil\n", entryName) + return nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return err + } + + switch o.(type) { + + case pdf.StreamDict: + // TODO validate 3D stream dict + + case pdf.Dict: + // TODO validate 3D reference dict + + default: + return errors.Errorf("pdfcpu: validateStreamDictOrDictEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + log.Validate.Printf("validateStreamDictOrDictEntry end: entry=%s\n", entryName) + + return nil +} + +func validateIntegerOrArrayOfIntegerEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + log.Validate.Printf("validateIntegerOrArrayOfIntegerEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return err + } + if o == nil { + if required { + return errors.Errorf("pdfcpu: validateIntegerOrArrayOfIntegerEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateIntegerOrArrayOfIntegerEntry end: optional entry %s is nil\n", entryName) + return nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return err + } + + switch o := o.(type) { + + case pdf.Integer: + // no further processing + + case pdf.Array: + + for i, o := range o { + + o, err := xRefTable.Dereference(o) + if err != nil { + return err + } + + if o == nil { + continue + } + + _, ok := o.(pdf.Integer) + if !ok { + return errors.Errorf("pdfcpu: validateIntegerOrArrayOfIntegerEntry: dict=%s entry=%s invalid type at index %d\n", dictName, entryName, i) + } + + } + + default: + return errors.Errorf("pdfcpu: validateIntegerOrArrayOfIntegerEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + log.Validate.Printf("validateIntegerOrArrayOfIntegerEntry end: entry=%s\n", entryName) + + return nil +} + +func validateNameOrArrayOfNameEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + log.Validate.Printf("validateNameOrArrayOfNameEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return err + } + if o == nil { + if required { + return errors.Errorf("pdfcpu: validateNameOrArrayOfNameEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateNameOrArrayOfNameEntry end: optional entry %s is nil\n", entryName) + return nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + // no further processing + + case pdf.Array: + + for i, o := range o { + + o, err := xRefTable.Dereference(o) + if err != nil { + return err + } + + if o == nil { + continue + } + + _, ok := o.(pdf.Name) + if !ok { + err = errors.Errorf("pdfcpu: validateNameOrArrayOfNameEntry: dict=%s entry=%s invalid type at index %d\n", dictName, entryName, i) + return err + } + + } + + default: + return errors.Errorf("pdfcpu: validateNameOrArrayOfNameEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + log.Validate.Printf("validateNameOrArrayOfNameEntry end: entry=%s\n", entryName) + + return nil +} + +func validateBooleanOrArrayOfBooleanEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + log.Validate.Printf("validateBooleanOrArrayOfBooleanEntry begin: entry=%s\n", entryName) + + o, err := d.Entry(dictName, entryName, required) + if err != nil || o == nil { + return err + } + + o, err = xRefTable.Dereference(o) + if err != nil { + return err + } + if o == nil { + if required { + return errors.Errorf("pdfcpu: validateBooleanOrArrayOfBooleanEntry: dict=%s required entry=%s is nil", dictName, entryName) + } + log.Validate.Printf("validateBooleanOrArrayOfBooleanEntry end: optional entry %s is nil\n", entryName) + return nil + } + + // Version check + err = xRefTable.ValidateVersion(fmt.Sprintf("dict=%s entry=%s", dictName, entryName), sinceVersion) + if err != nil { + return err + } + + switch o := o.(type) { + + case pdf.Boolean: + // no further processing + + case pdf.Array: + + for i, o := range o { + + o, err := xRefTable.Dereference(o) + if err != nil { + return err + } + + if o == nil { + continue + } + + _, ok := o.(pdf.Boolean) + if !ok { + return errors.Errorf("pdfcpu: validateBooleanOrArrayOfBooleanEntry: dict=%s entry=%s invalid type at index %d\n", dictName, entryName, i) + } + + } + + default: + return errors.Errorf("pdfcpu: validateBooleanOrArrayOfBooleanEntry: dict=%s entry=%s invalid type", dictName, entryName) + } + + log.Validate.Printf("validateBooleanOrArrayOfBooleanEntry end: entry=%s\n", entryName) + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/optionalContent.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/optionalContent.go new file mode 100644 index 0000000..a5dfff4 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/optionalContent.go @@ -0,0 +1,456 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateOptionalContentGroupIntent(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + // see 8.11.2.1 + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + validate := func(s string) bool { + return s == "View" || s == "Design" || s == "All" + } + + switch o := o.(type) { + + case pdf.Name: + if !validate(o.Value()) { + return errors.Errorf("validateOptionalContentGroupIntent: invalid intent: %s", o.Value()) + } + + case pdf.Array: + + for i, v := range o { + + if v == nil { + continue + } + + n, ok := v.(pdf.Name) + if !ok { + return errors.Errorf("pdfcpu: validateOptionalContentGroupIntent: invalid type at index %d\n", i) + } + + if !validate(n.Value()) { + return errors.Errorf("pdfcpu: validateOptionalContentGroupIntent: invalid intent: %s", n.Value()) + } + } + + default: + return errors.New("pdfcpu: validateOptionalContentGroupIntent: invalid type") + } + + return nil +} + +func validateOptionalContentGroupUsageDict(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + // see 8.11.4.4 + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + dictName = "OCUsageDict" + + // CreatorInfo, optional, dict + _, err = validateDictEntry(xRefTable, d1, dictName, "CreatorInfo", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // Language, optional, dict + _, err = validateDictEntry(xRefTable, d1, dictName, "Language", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // Export, optional, dict + _, err = validateDictEntry(xRefTable, d1, dictName, "Export", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // Zoom, optional, dict + _, err = validateDictEntry(xRefTable, d1, dictName, "Zoom", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // Print, optional, dict + _, err = validateDictEntry(xRefTable, d1, dictName, "Print", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // View, optional, dict + _, err = validateDictEntry(xRefTable, d1, dictName, "View", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // User, optional, dict + _, err = validateDictEntry(xRefTable, d1, dictName, "User", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // PageElement, optional, dict + _, err = validateDictEntry(xRefTable, d1, dictName, "PageElement", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateOptionalContentGroupDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see 8.11 Optional Content + + dictName := "optionalContentGroupDict" + + // Type, required, name, OCG + _, err := validateNameEntry(xRefTable, d, dictName, "Type", REQUIRED, sinceVersion, func(s string) bool { return s == "OCG" }) + if err != nil { + return err + } + + // Name, required, text string + _, err = validateStringEntry(xRefTable, d, dictName, "Name", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + // Intent, optional, name or array + err = validateOptionalContentGroupIntent(xRefTable, d, dictName, "Intent", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // Usage, optional, usage dict + return validateOptionalContentGroupUsageDict(xRefTable, d, dictName, "Usage", OPTIONAL, sinceVersion) +} + +func validateOptionalContentGroupArray(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, dictEntry string, sinceVersion pdf.Version) error { + + a, err := validateArrayEntry(xRefTable, d, dictName, dictEntry, OPTIONAL, sinceVersion, nil) + if err != nil || a == nil { + return err + } + + for _, v := range a { + + if v == nil { + continue + } + + d, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateOptionalContentGroupDict(xRefTable, d, sinceVersion) + if err != nil { + return err + } + + } + + return nil +} + +func validateOCGs(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, sinceVersion pdf.Version) error { + + // see 8.11.2.2 + + o, err := d.Entry(dictName, entryName, OPTIONAL) + if err != nil || o == nil { + return err + } + + // Version check + err = xRefTable.ValidateVersion("OCGs", sinceVersion) + if err != nil { + return err + } + + o, err = xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + d1, ok := o.(pdf.Dict) + if ok { + return validateOptionalContentGroupDict(xRefTable, d1, sinceVersion) + } + + return validateOptionalContentGroupArray(xRefTable, d, dictName, entryName, sinceVersion) +} + +func validateOptionalContentMembershipDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + // see 8.11.2.2 + + dictName := "OCMDict" + + // OCGs, optional, dict or array + err := validateOCGs(xRefTable, d, dictName, "OCGs", sinceVersion) + if err != nil { + return err + } + + // P, optional, name + validate := func(s string) bool { return pdf.MemberOf(s, []string{"AllOn", "AnyOn", "AnyOff", "AllOff"}) } + _, err = validateNameEntry(xRefTable, d, dictName, "P", OPTIONAL, sinceVersion, validate) + if err != nil { + return err + } + + // VE, optional, array, since V1.6 + _, err = validateArrayEntry(xRefTable, d, dictName, "VE", OPTIONAL, pdf.V16, nil) + + return err +} + +func validateOptionalContent(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + validate := func(s string) bool { return s == "OCG" || s == "OCMD" } + t, err := validateNameEntry(xRefTable, d1, "optionalContent", "Type", REQUIRED, sinceVersion, validate) + if err != nil { + return err + } + + if *t == "OCG" { + return validateOptionalContentGroupDict(xRefTable, d1, sinceVersion) + } + + return validateOptionalContentMembershipDict(xRefTable, d1, sinceVersion) +} + +func validateUsageApplicationDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "usageAppDict" + + // Event, required, name + _, err := validateNameEntry(xRefTable, d, dictName, "Event", REQUIRED, sinceVersion, func(s string) bool { return s == "View" || s == "Print" || s == "Export" }) + if err != nil { + return err + } + + // OCGs, optional, array of content groups + err = validateOptionalContentGroupArray(xRefTable, d, dictName, "OCGs", sinceVersion) + if err != nil { + return err + } + + // Category, required, array of names + _, err = validateNameArrayEntry(xRefTable, d, dictName, "Category", REQUIRED, sinceVersion, nil) + + return err +} + +func validateUsageApplicationDictArray(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, dictEntry string, required bool, sinceVersion pdf.Version) error { + + a, err := validateArrayEntry(xRefTable, d, dictName, dictEntry, required, sinceVersion, nil) + if err != nil || a == nil { + return err + } + + for _, v := range a { + + if v == nil { + continue + } + + d, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateUsageApplicationDict(xRefTable, d, sinceVersion) + if err != nil { + return err + } + + } + + return nil +} + +func validateOptionalContentConfigurationDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "optContentConfigDict" + + // Name, optional, string + _, err := validateStringEntry(xRefTable, d, dictName, "Name", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // Creator, optional, string + _, err = validateStringEntry(xRefTable, d, dictName, "Creator", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // BaseState, optional, name + validate := func(s string) bool { return pdf.MemberOf(s, []string{"ON", "OFF", "UNCHANGED"}) } + baseState, err := validateNameEntry(xRefTable, d, dictName, "BaseState", OPTIONAL, sinceVersion, validate) + if err != nil { + return err + } + + if baseState != nil { + + if baseState.Value() != "ON" { + // ON, optional, content group array + err = validateOptionalContentGroupArray(xRefTable, d, dictName, "ON", sinceVersion) + if err != nil { + return err + } + } + + if baseState.Value() != "OFF" { + // OFF, optional, content group array + err = validateOptionalContentGroupArray(xRefTable, d, dictName, "OFF", sinceVersion) + if err != nil { + return err + } + } + + } + + // Intent, optional, name or array + err = validateOptionalContentGroupIntent(xRefTable, d, dictName, "Intent", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // AS, optional, usage application dicts array + err = validateUsageApplicationDictArray(xRefTable, d, dictName, "AS", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // Order, optional, array + _, err = validateArrayEntry(xRefTable, d, dictName, "Order", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // ListMode, optional, name + validate = func(s string) bool { return pdf.MemberOf(s, []string{"AllPages", "VisiblePages"}) } + _, err = validateNameEntry(xRefTable, d, dictName, "ListMode", OPTIONAL, sinceVersion, validate) + if err != nil { + return err + } + + // RBGroups, optional, array + _, err = validateArrayEntry(xRefTable, d, dictName, "RBGroups", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // Locked, optional, array + return validateOptionalContentGroupArray(xRefTable, d, dictName, "Locked", pdf.V16) +} + +func validateOCProperties(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // aka optional content properties dict. + + // => 8.11.4 Configuring Optional Content + + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V14 + } + + d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "OCProperties", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + dictName := "optContentPropertiesDict" + + // "OCGs" required array of already written indRefs + r := true + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + r = false + } + _, err = validateIndRefArrayEntry(xRefTable, d, dictName, "OCGs", r, sinceVersion, nil) + if err != nil { + return err + } + + // "D" required dict, default viewing optional content configuration dict. + d1, err := validateDictEntry(xRefTable, d, dictName, "D", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + err = validateOptionalContentConfigurationDict(xRefTable, d1, sinceVersion) + if err != nil { + return err + } + + // "Configs" optional array of alternate optional content configuration dicts. + a, err := validateArrayEntry(xRefTable, d, dictName, "Configs", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if a != nil { + for _, o := range a { + + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateOptionalContentConfigurationDict(xRefTable, d, sinceVersion) + if err != nil { + return err + } + + } + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/outlineTree.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/outlineTree.go new file mode 100644 index 0000000..a6b3999 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/outlineTree.go @@ -0,0 +1,172 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateOutlineItemDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "outlineItemDict" + + // Title, required, text string + _, err := validateStringEntry(xRefTable, d, dictName, "Title", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // fmt.Printf("Title: %s\n", *title) + + // Parent, required, dict indRef + ir, err := validateIndRefEntry(xRefTable, d, dictName, "Parent", REQUIRED, pdf.V10) + if err != nil { + return err + } + _, err = xRefTable.DereferenceDict(*ir) + if err != nil { + return err + } + + // Count, optional, int + _, err = validateIntegerEntry(xRefTable, d, dictName, "Count", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // SE, optional, dict indRef, since V1.3 + ir, err = validateIndRefEntry(xRefTable, d, dictName, "SE", OPTIONAL, pdf.V13) + if err != nil { + return err + } + if ir != nil { + _, err = xRefTable.DereferenceDict(*ir) + if err != nil { + return err + } + } + + // C, optional, array of 3 numbers, since V1.4 + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "C", OPTIONAL, pdf.V14, func(a pdf.Array) bool { return len(a) == 3 }) + if err != nil { + return err + } + + // F, optional integer, since V1.4 + _, err = validateIntegerEntry(xRefTable, d, dictName, "F", OPTIONAL, pdf.V14, nil) + if err != nil { + return err + } + + // Optional A or Dest, since V1.1 + return validateActionOrDestination(xRefTable, d, dictName, pdf.V11) +} + +func validateOutlineTree(xRefTable *pdf.XRefTable, first, last *pdf.IndirectRef) error { + + var ( + d pdf.Dict + objNumber int + err error + ) + + // Process linked list of outline items. + for ir := first; ir != nil; ir = d.IndirectRefEntry("Next") { + + objNumber = ir.ObjectNumber.Value() + + // outline item dict + d, err = xRefTable.DereferenceDict(*ir) + if err != nil { + return err + } + if d == nil { + return errors.Errorf("validateOutlineTree: object #%d is nil.", objNumber) + } + + err = validateOutlineItemDict(xRefTable, d) + if err != nil { + return err + } + + firstChild := d.IndirectRefEntry("First") + lastChild := d.IndirectRefEntry("Last") + + if firstChild == nil && lastChild == nil { + // Leaf + continue + } + + if firstChild != nil && (xRefTable.ValidationMode == pdf.ValidationRelaxed || + xRefTable.ValidationMode == pdf.ValidationStrict && lastChild != nil) { + // Recurse into subtree. + err = validateOutlineTree(xRefTable, firstChild, lastChild) + if err != nil { + return err + } + continue + } + + return errors.New("pdfcpu: validateOutlineTree: corrupted, needs both first and last or neither for a leaf") + + } + + if xRefTable.ValidationMode == pdf.ValidationStrict && objNumber != last.ObjectNumber.Value() { + return errors.Errorf("pdfcpu: validateOutlineTree: corrupted child list %d <> %d\n", objNumber, last.ObjectNumber) + } + + return nil +} + +func validateOutlines(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 12.3.3 Document Outline + + ir, err := validateIndRefEntry(xRefTable, rootDict, "rootDict", "Outlines", OPTIONAL, sinceVersion) + if err != nil || ir == nil { + return err + } + + d, err := xRefTable.DereferenceDict(*ir) + if err != nil || d == nil { + return err + } + + // Type, optional, name + _, err = validateNameEntry(xRefTable, d, "outlineDict", "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "Outlines" || s == "Outline" }) + if err != nil { + return err + } + + first := d.IndirectRefEntry("First") + last := d.IndirectRefEntry("Last") + + if first == nil { + if last != nil { + return errors.New("pdfcpu: validateOutlines: corrupted, root needs both first and last") + } + // leaf + return nil + } + + if xRefTable.ValidationMode == pdf.ValidationStrict && last == nil { + return errors.New("pdfcpu: validateOutlines: corrupted, root needs both first and last") + } + + return validateOutlineTree(xRefTable, first, last) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/pages.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/pages.go new file mode 100644 index 0000000..63dae01 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/pages.go @@ -0,0 +1,1011 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + "github.com/pdfcpu/pdfcpu/pkg/log" + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateResourceDict(xRefTable *pdf.XRefTable, o pdf.Object) (hasResources bool, err error) { + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return false, err + } + + for k, v := range map[string]struct { + validate func(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error + sinceVersion pdf.Version + }{ + "ExtGState": {validateExtGStateResourceDict, pdf.V10}, + "Font": {validateFontResourceDict, pdf.V10}, + "XObject": {validateXObjectResourceDict, pdf.V10}, + "Properties": {validatePropertiesResourceDict, pdf.V10}, + "ColorSpace": {validateColorSpaceResourceDict, pdf.V10}, + "Pattern": {validatePatternResourceDict, pdf.V10}, + "Shading": {validateShadingResourceDict, pdf.V13}, + } { + if o, ok := d.Find(k); ok { + err = v.validate(xRefTable, o, v.sinceVersion) + if err != nil { + return false, err + } + } + } + + allowedResDictKeys := []string{"ExtGState", "Font", "XObject", "Properties", "ColorSpace", "Pattern", "ProcSet", "Shading"} + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + allowedResDictKeys = append(allowedResDictKeys, "Encoding") + allowedResDictKeys = append(allowedResDictKeys, "ProcSets") + } + + // Note: Beginning with PDF V1.4 the "ProcSet" feature is considered to be obsolete! + + for k := range d { + if !pdf.MemberOf(k, allowedResDictKeys) { + d.Delete(k) + } + } + + return true, nil +} + +func validatePageContents(xRefTable *pdf.XRefTable, d pdf.Dict) (hasContents bool, err error) { + + o, found := d.Find("Contents") + if !found { + return false, err + } + + o, err = xRefTable.Dereference(o) + if err != nil || o == nil { + return false, err + } + + switch o := o.(type) { + + case pdf.StreamDict: + // no further processing. + hasContents = true + + case pdf.Array: + // process array of content stream dicts. + + for _, o := range o { + o, _, err = xRefTable.DereferenceStreamDict(o) + if err != nil { + return false, err + } + + if o == nil { + continue + } + + hasContents = true + + } + + default: + return false, errors.Errorf("validatePageContents: page content must be stream dict or array") + } + + return hasContents, nil +} + +func validatePageResources(xRefTable *pdf.XRefTable, d pdf.Dict, hasResources, hasContents bool) error { + + if o, found := d.Find("Resources"); found { + _, err := validateResourceDict(xRefTable, o) + return err + } + + // TODO Check if contents need resources (#169) + // if !hasResources && hasContents { + // return errors.New("pdfcpu: validatePageResources: missing required entry \"Resources\" - should be inherited") + // } + + return nil +} + +func validatePageEntryMediaBox(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) (hasMediaBox bool, err error) { + + o, err := validateRectangleEntry(xRefTable, d, "pageDict", "MediaBox", required, sinceVersion, nil) + if err != nil { + return false, err + } + if o != nil { + hasMediaBox = true + } + + return hasMediaBox, nil +} + +func validatePageEntryCropBox(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validateRectangleEntry(xRefTable, d, "pagesDict", "CropBox", required, sinceVersion, nil) + + return err +} + +func validatePageEntryBleedBox(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validateRectangleEntry(xRefTable, d, "pagesDict", "BleedBox", required, sinceVersion, nil) + + return err +} + +func validatePageEntryTrimBox(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validateRectangleEntry(xRefTable, d, "pagesDict", "TrimBox", required, sinceVersion, nil) + + return err +} + +func validatePageEntryArtBox(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validateRectangleEntry(xRefTable, d, "pagesDict", "ArtBox", required, sinceVersion, nil) + + return err +} + +func validateBoxStyleDictEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + dictName = "boxStyleDict" + + // C, number array with 3 elements, optional + _, err = validateNumberArrayEntry(xRefTable, d1, dictName, "C", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 3 }) + if err != nil { + return err + } + + // W, number, optional + _, err = validateNumberEntry(xRefTable, d1, dictName, "W", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // S, name, optional + validate := func(s string) bool { return pdf.MemberOf(s, []string{"S", "D"}) } + _, err = validateNameEntry(xRefTable, d1, dictName, "S", OPTIONAL, sinceVersion, validate) + if err != nil { + return err + } + + // D, array, optional, since V1.3, dashArray + _, err = validateIntegerArrayEntry(xRefTable, d1, dictName, "D", OPTIONAL, sinceVersion, nil) + + return err +} + +func validatePageBoxColorInfo(xRefTable *pdf.XRefTable, pageDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // box color information dict + // see 14.11.2.2 + + dictName := "pageDict" + + d, err := validateDictEntry(xRefTable, pageDict, dictName, "BoxColorInfo", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + dictName = "boxColorInfoDict" + + err = validateBoxStyleDictEntry(xRefTable, d, dictName, "CropBox", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + err = validateBoxStyleDictEntry(xRefTable, d, dictName, "BleedBox", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + err = validateBoxStyleDictEntry(xRefTable, d, dictName, "TrimBox", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + return validateBoxStyleDictEntry(xRefTable, d, dictName, "ArtBox", OPTIONAL, sinceVersion) +} + +func validatePageEntryRotate(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + validate := func(i int) bool { return i%90 == 0 } + _, err := validateIntegerEntry(xRefTable, d, "pagesDict", "Rotate", required, sinceVersion, validate) + + return err +} + +func validatePageEntryGroup(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + + d1, err := validateDictEntry(xRefTable, d, "pageDict", "Group", required, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateGroupAttributesDict(xRefTable, d1) + } + + return err +} + +func validatePageEntryThumb(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + sd, err := validateStreamDictEntry(xRefTable, d, "pagesDict", "Thumb", required, sinceVersion, nil) + if err != nil || sd == nil { + return err + } + + return validateXObjectStreamDict(xRefTable, *sd) +} + +func validatePageEntryB(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // Note: Only makes sense if "Threads" entry in document root and bead dicts present. + + _, err := validateIndRefArrayEntry(xRefTable, d, "pagesDict", "B", required, sinceVersion, nil) + + return err +} + +func validatePageEntryDur(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validateNumberEntry(xRefTable, d, "pagesDict", "Dur", required, sinceVersion, nil) + + return err +} + +func validateTransitionDictEntryDi(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + o, found := d.Find("Di") + if !found { + return nil + } + + switch o := o.(type) { + + case pdf.Integer: + validate := func(i int) bool { return pdf.IntMemberOf(i, []int{0, 90, 180, 270, 315}) } + if !validate(o.Value()) { + return errors.New("pdfcpu: validateTransitionDict: entry Di int value undefined") + } + + case pdf.Name: + if o.Value() != "None" { + return errors.New("pdfcpu: validateTransitionDict: entry Di name value undefined") + } + } + + return nil +} + +func validateTransitionDictEntryM(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, transStyle *pdf.Name) error { + + // see 12.4.4 + validateTransitionDirectionOfMotion := func(s string) bool { return pdf.MemberOf(s, []string{"I", "O"}) } + + validateM := func(s string) bool { + return validateTransitionDirectionOfMotion(s) && + (transStyle != nil && (*transStyle == "Split" || *transStyle == "Box" || *transStyle == "Fly")) + } + + _, err := validateNameEntry(xRefTable, d, dictName, "M", OPTIONAL, pdf.V10, validateM) + + return err +} + +func validateTransitionDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "transitionDict" + + // S, name, optional + + validateTransitionStyle := func(s string) bool { + return pdf.MemberOf(s, []string{"Split", "Blinds", "Box", "Wipe", "Dissolve", "Glitter", "R"}) + } + + validate := validateTransitionStyle + + if xRefTable.Version() >= pdf.V15 { + validate = func(s string) bool { + + if validateTransitionStyle(s) { + return true + } + + return pdf.MemberOf(s, []string{"Fly", "Push", "Cover", "Uncover", "Fade"}) + } + } + transStyle, err := validateNameEntry(xRefTable, d, dictName, "S", OPTIONAL, pdf.V10, validate) + if err != nil { + return err + } + + // D, optional, number > 0 + _, err = validateNumberEntry(xRefTable, d, dictName, "D", OPTIONAL, pdf.V10, func(f float64) bool { return f > 0 }) + if err != nil { + return err + } + + // Dm, optional, name, see 12.4.4 + validateTransitionDimension := func(s string) bool { return pdf.MemberOf(s, []string{"H", "V"}) } + + validateDm := func(s string) bool { + return validateTransitionDimension(s) && (transStyle != nil && (*transStyle == "Split" || *transStyle == "Blinds")) + } + _, err = validateNameEntry(xRefTable, d, dictName, "Dm", OPTIONAL, pdf.V10, validateDm) + if err != nil { + return err + } + + // M, optional, name + err = validateTransitionDictEntryM(xRefTable, d, dictName, transStyle) + if err != nil { + return err + } + + // Di, optional, number or name + err = validateTransitionDictEntryDi(xRefTable, d) + if err != nil { + return err + } + + // SS, optional, number, since V1.5 + if transStyle != nil && *transStyle == "Fly" { + _, err = validateNumberEntry(xRefTable, d, dictName, "SS", OPTIONAL, pdf.V15, nil) + if err != nil { + return err + } + } + + // B, optional, boolean, since V1.5 + validateB := func(b bool) bool { return transStyle != nil && *transStyle == "Fly" } + _, err = validateBooleanEntry(xRefTable, d, dictName, "B", OPTIONAL, pdf.V15, validateB) + + return err +} + +func validatePageEntryTrans(xRefTable *pdf.XRefTable, pageDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + d, err := validateDictEntry(xRefTable, pageDict, "pagesDict", "Trans", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + return validateTransitionDict(xRefTable, d) +} + +func validatePageEntryStructParents(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validateIntegerEntry(xRefTable, d, "pagesDict", "StructParents", required, sinceVersion, nil) + + return err +} + +func validatePageEntryID(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validateStringEntry(xRefTable, d, "pagesDict", "ID", required, sinceVersion, nil) + + return err +} + +func validatePageEntryPZ(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // Preferred zoom factor, number + + _, err := validateNumberEntry(xRefTable, d, "pagesDict", "PZ", required, sinceVersion, nil) + + return err +} + +func validatePageEntrySeparationInfo(xRefTable *pdf.XRefTable, pagesDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // see 14.11.4 + + d, err := validateDictEntry(xRefTable, pagesDict, "pagesDict", "SeparationInfo", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + dictName := "separationDict" + + _, err = validateIndRefArrayEntry(xRefTable, d, dictName, "Pages", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + err = validateNameOrStringEntry(xRefTable, d, dictName, "DeviceColorant", required, sinceVersion) + if err != nil { + return err + } + + a, err := validateArrayEntry(xRefTable, d, dictName, "ColorSpace", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if a != nil { + err = validateColorSpaceArraySubset(xRefTable, a, []string{"Separation", "DeviceN"}) + } + + return err +} + +func validatePageEntryTabs(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + validateTabs := func(s string) bool { return pdf.MemberOf(s, []string{"R", "C", "S", "A", "W"}) } + + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V14 + } + _, err := validateNameEntry(xRefTable, d, "pagesDict", "Tabs", required, sinceVersion, validateTabs) + + return err +} + +func validatePageEntryTemplateInstantiated(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // see 12.7.6 + + _, err := validateNameEntry(xRefTable, d, "pagesDict", "TemplateInstantiated", required, sinceVersion, nil) + + return err +} + +// TODO implement +func validatePageEntryPresSteps(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // see 12.4.4.2 + + d1, err := validateDictEntry(xRefTable, d, "pagesDict", "PresSteps", required, sinceVersion, nil) + if err != nil || d1 == nil { + return err + } + + return errors.New("pdfcpu: validatePageEntryPresSteps: not supported") +} + +func validatePageEntryUserUnit(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // UserUnit, optional, positive number, since V1.6 + _, err := validateNumberEntry(xRefTable, d, "pagesDict", "UserUnit", required, sinceVersion, func(f float64) bool { return f > 0 }) + + return err +} + +func validateNumberFormatDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "numberFormatDict" + + // Type, name, optional + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "NumberFormat" }) + if err != nil { + return err + } + + // U, text string, required + _, err = validateStringEntry(xRefTable, d, dictName, "U", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + // C, number, required + _, err = validateNumberEntry(xRefTable, d, dictName, "C", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + // F, name, optional + _, err = validateNameEntry(xRefTable, d, dictName, "F", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // D, integer, optional + _, err = validateIntegerEntry(xRefTable, d, dictName, "D", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // FD, bool, optional + _, err = validateBooleanEntry(xRefTable, d, dictName, "FD", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // RT, text string, optional + _, err = validateStringEntry(xRefTable, d, dictName, "RT", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // RD, text string, optional + _, err = validateStringEntry(xRefTable, d, dictName, "RD", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // PS, text string, optional + _, err = validateStringEntry(xRefTable, d, dictName, "PS", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // SS, text string, optional + _, err = validateStringEntry(xRefTable, d, dictName, "SS", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // O, name, optional + _, err = validateNameEntry(xRefTable, d, dictName, "O", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateNumberFormatArrayEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + a, err := validateArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || a == nil { + return err + } + + for _, v := range a { + + d, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateNumberFormatDict(xRefTable, d, sinceVersion) + if err != nil { + return err + } + + } + + return nil +} + +func validateMeasureDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "measureDict" + + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Measure" }) + if err != nil { + return err + } + + // PDF 1.6 defines only a single type of coordinate system, a rectilinear coordinate system, + // that shall be specified by the value RL for the Subtype entry. + coordSys, err := validateNameEntry(xRefTable, d, dictName, "Subtype", OPTIONAL, sinceVersion, nil) + if err != nil || coordSys == nil { + return err + } + + if *coordSys != "RL" { + if xRefTable.Version() > sinceVersion { + // unknown coord system + return nil + } + return errors.Errorf("validateMeasureDict dict=%s entry=%s invalid dict entry: %s", dictName, "Subtype", coordSys.Value()) + } + + // R, text string, required, scale ratio + _, err = validateStringEntry(xRefTable, d, dictName, "R", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + // X, number format array, required, for measurement of change along the x axis and, if Y is not present, along the y axis as well. + err = validateNumberFormatArrayEntry(xRefTable, d, dictName, "X", REQUIRED, sinceVersion) + if err != nil { + return err + } + + // Y, number format array, required when the x and y scales have different units or conversion factors. + err = validateNumberFormatArrayEntry(xRefTable, d, dictName, "Y", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // D, number format array, required, for measurement of distance in any direction. + err = validateNumberFormatArrayEntry(xRefTable, d, dictName, "D", REQUIRED, sinceVersion) + if err != nil { + return err + } + + // A, number format array, required, for measurement of area. + err = validateNumberFormatArrayEntry(xRefTable, d, dictName, "A", REQUIRED, sinceVersion) + if err != nil { + return err + } + + // T, number format array, optional, for measurement of angles. + err = validateNumberFormatArrayEntry(xRefTable, d, dictName, "T", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // S, number format array, optional, for fmeasurement of the slope of a line. + err = validateNumberFormatArrayEntry(xRefTable, d, dictName, "S", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // O, number array, optional, array of two numbers that shall specify the origin of the measurement coordinate system in default user space coordinates. + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "O", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + // CYX, number, optional, a factor that shall be used to convert the largest units along the y axis to the largest units along the x axis. + _, err = validateNumberEntry(xRefTable, d, dictName, "CYX", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + return nil +} + +func validateViewportDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "viewportDict" + + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Viewport" }) + if err != nil { + return err + } + + _, err = validateRectangleEntry(xRefTable, d, dictName, "BBox", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateStringEntry(xRefTable, d, dictName, "Name", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // Measure, optional, dict + d1, err := validateDictEntry(xRefTable, d, dictName, "Measure", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateMeasureDict(xRefTable, d1, sinceVersion) + } + + return err +} + +func validatePageEntryVP(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // see table 260 + + a, err := validateArrayEntry(xRefTable, d, "pagesDict", "VP", required, sinceVersion, nil) + if err != nil || a == nil { + return err + } + + for _, v := range a { + + if v == nil { + continue + } + + d, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateViewportDict(xRefTable, d, sinceVersion) + if err != nil { + return err + } + + } + + return nil +} + +func validatePageDict(xRefTable *pdf.XRefTable, d pdf.Dict, objNumber, genNumber int, hasResources, hasMediaBox bool) error { + + dictName := "pageDict" + + if ir := d.IndirectRefEntry("Parent"); ir == nil { + return errors.New("pdfcpu: validatePageDict: missing parent") + } + + // Contents + hasContents, err := validatePageContents(xRefTable, d) + if err != nil { + return err + } + + // Resources + err = validatePageResources(xRefTable, d, hasResources, hasContents) + if err != nil { + return err + } + + // MediaBox + _, err = validatePageEntryMediaBox(xRefTable, d, !hasMediaBox, pdf.V10) + if err != nil { + return err + } + + // PieceInfo + sinceVersion := pdf.V13 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V10 + } + hasPieceInfo, err := validatePieceInfo(xRefTable, d, dictName, "PieceInfo", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // LastModified + lm, err := validateDateEntry(xRefTable, d, dictName, "LastModified", OPTIONAL, pdf.V13) + if err != nil { + return err + } + + if hasPieceInfo && lm == nil && xRefTable.ValidationMode == pdf.ValidationStrict { + return errors.New("pdfcpu: validatePageDict: missing \"LastModified\" (required by \"PieceInfo\")") + } + + // AA + err = validateAdditionalActions(xRefTable, d, dictName, "AA", OPTIONAL, pdf.V14, "page") + if err != nil { + return err + } + + type v struct { + validate func(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) (err error) + required bool + sinceVersion pdf.Version + } + + for _, f := range []v{ + {validatePageEntryCropBox, OPTIONAL, pdf.V10}, + {validatePageEntryBleedBox, OPTIONAL, pdf.V13}, + {validatePageEntryTrimBox, OPTIONAL, pdf.V13}, + {validatePageEntryArtBox, OPTIONAL, pdf.V13}, + {validatePageBoxColorInfo, OPTIONAL, pdf.V14}, + {validatePageEntryRotate, OPTIONAL, pdf.V10}, + {validatePageEntryGroup, OPTIONAL, pdf.V14}, + {validatePageEntryThumb, OPTIONAL, pdf.V10}, + {validatePageEntryB, OPTIONAL, pdf.V11}, + {validatePageEntryDur, OPTIONAL, pdf.V11}, + {validatePageEntryTrans, OPTIONAL, pdf.V11}, + {validateMetadata, OPTIONAL, pdf.V14}, + {validatePageEntryStructParents, OPTIONAL, pdf.V10}, + {validatePageEntryID, OPTIONAL, pdf.V13}, + {validatePageEntryPZ, OPTIONAL, pdf.V13}, + {validatePageEntrySeparationInfo, OPTIONAL, pdf.V13}, + {validatePageEntryTabs, OPTIONAL, pdf.V15}, + {validatePageEntryTemplateInstantiated, OPTIONAL, pdf.V15}, + {validatePageEntryPresSteps, OPTIONAL, pdf.V15}, + {validatePageEntryUserUnit, OPTIONAL, pdf.V16}, + {validatePageEntryVP, OPTIONAL, pdf.V16}, + } { + err = f.validate(xRefTable, d, f.required, f.sinceVersion) + if err != nil { + return err + } + } + + return nil +} + +func validatePagesDictGeneralEntries(xRefTable *pdf.XRefTable, d pdf.Dict) (hasResources, hasMediaBox bool, err error) { + + hasResources, err = validateResources(xRefTable, d) + if err != nil { + return false, false, err + } + + // MediaBox: optional, rectangle + hasMediaBox, err = validatePageEntryMediaBox(xRefTable, d, OPTIONAL, pdf.V10) + if err != nil { + return false, false, err + } + + // CropBox: optional, rectangle + err = validatePageEntryCropBox(xRefTable, d, OPTIONAL, pdf.V10) + if err != nil { + return false, false, err + } + + // Rotate: optional, integer + err = validatePageEntryRotate(xRefTable, d, OPTIONAL, pdf.V10) + if err != nil { + return false, false, err + } + + return hasResources, hasMediaBox, nil +} + +func dictTypeForPageNodeDict(d pdf.Dict) (string, error) { + + if d == nil { + return "", errors.New("pdfcpu: dictTypeForPageNodeDict: pageNodeDict is null") + } + + dictType := d.Type() + if dictType == nil { + return "", errors.New("pdfcpu: dictTypeForPageNodeDict: missing pageNodeDict type") + } + + return *dictType, nil +} + +func validateResources(xRefTable *pdf.XRefTable, d pdf.Dict) (hasResources bool, err error) { + + // Get number of pages of this PDF file. + pageCount := d.IntEntry("Count") + if pageCount == nil { + return false, errors.New("pdfcpu: validateResources: missing \"Count\"") + } + + // TODO not ideal - overall pageCount is only set during validation! + if xRefTable.PageCount == 0 { + xRefTable.PageCount = *pageCount + } + + log.Validate.Printf("validateResources: This page node has %d pages\n", *pageCount) + + // Resources: optional, dict + o, ok := d.Find("Resources") + if !ok { + return false, nil + } + + return validateResourceDict(xRefTable, o) +} + +func validatePagesDict(xRefTable *pdf.XRefTable, d pdf.Dict, objNr, genNumber int, hasResources, hasMediaBox bool) error { + + // Resources and Mediabox are inherited. + //var dHasResources, dHasMediaBox bool + dHasResources, dHasMediaBox, err := validatePagesDictGeneralEntries(xRefTable, d) + if err != nil { + return err + } + + if dHasResources { + hasResources = true + } + + if dHasMediaBox { + hasMediaBox = true + } + + // Iterate over page tree. + kidsArray := d.ArrayEntry("Kids") + if kidsArray == nil { + return errors.New("pdfcpu: validatePagesDict: corrupt \"Kids\" entry") + } + + for _, o := range kidsArray { + + if o == nil { + continue + } + + // Dereference next page node dict. + ir, ok := o.(pdf.IndirectRef) + if !ok { + return errors.New("pdfcpu: validatePagesDict: missing indirect reference for kid") + } + + log.Validate.Printf("validatePagesDict: PageNode: %s\n", ir) + + objNumber := ir.ObjectNumber.Value() + genNumber := ir.GenerationNumber.Value() + + pageNodeDict, err := xRefTable.DereferenceDict(ir) + if err != nil { + return err + } + + // Validate this kid's parent. + parentIndRef := pageNodeDict.IndirectRefEntry("Parent") + if parentIndRef.ObjectNumber.Value() != objNr { + return errors.New("pdfcpu: validatePagesDict: corrupt parent node") + } + + dictType, err := dictTypeForPageNodeDict(pageNodeDict) + if err != nil { + return err + } + + switch dictType { + + case "Pages": + // Recurse over pagetree + err = validatePagesDict(xRefTable, pageNodeDict, objNumber, genNumber, hasResources, hasMediaBox) + + case "Page": + err = validatePageDict(xRefTable, pageNodeDict, objNumber, genNumber, hasResources, hasMediaBox) + + default: + return errors.Errorf("pdfcpu: validatePagesDict: Unexpected dict type: %s", dictType) + + } + + if err != nil { + return err + } + + } + + return nil +} + +func validatePages(xRefTable *pdf.XRefTable, rootDict pdf.Dict) (pdf.Dict, error) { + + // Ensure indirect reference entry "Pages". + + ir := rootDict.IndirectRefEntry("Pages") + if ir == nil { + return nil, errors.New("pdfcpu: validatePages: missing indirect obj for pages dict") + } + + objNumber := ir.ObjectNumber.Value() + genNumber := ir.GenerationNumber.Value() + + // Dereference root of page node tree. + rootPageNodeDict, err := xRefTable.DereferenceDict(*ir) + if err != nil { + return nil, err + } + + if rootPageNodeDict == nil { + return nil, errors.New("pdfcpu: validatePagesDict: cannot dereference pageNodeDict") + } + + // Process page node tree. + err = validatePagesDict(xRefTable, rootPageNodeDict, objNumber, genNumber, false, false) + if err != nil { + return nil, err + } + + return rootPageNodeDict, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/pattern.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/pattern.go new file mode 100644 index 0000000..f9cb5e7 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/pattern.go @@ -0,0 +1,179 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateTilingPatternDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict, sinceVersion pdf.Version) error { + + dictName := "tilingPatternDict" + + // Version check + err := xRefTable.ValidateVersion(dictName, sinceVersion) + if err != nil { + return err + } + + _, err = validateNameEntry(xRefTable, sd.Dict, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Pattern" }) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "PatternType", REQUIRED, sinceVersion, func(i int) bool { return i == 1 }) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "PaintType", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "TilingType", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateRectangleEntry(xRefTable, sd.Dict, dictName, "BBox", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, sd.Dict, dictName, "XStep", REQUIRED, sinceVersion, func(f float64) bool { return f != 0 }) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, sd.Dict, dictName, "YStep", REQUIRED, sinceVersion, func(f float64) bool { return f != 0 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, sd.Dict, dictName, "Matrix", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 6 }) + if err != nil { + return err + } + + o, ok := sd.Find("Resources") + if !ok { + return errors.New("pdfcpu: validateTilingPatternDict: missing required entry Resources") + } + + _, err = validateResourceDict(xRefTable, o) + + return err +} + +func validateShadingPatternDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "shadingPatternDict" + + err := xRefTable.ValidateVersion(dictName, sinceVersion) + if err != nil { + return err + } + + _, err = validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Pattern" }) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, d, dictName, "PatternType", REQUIRED, sinceVersion, func(i int) bool { return i == 2 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Matrix", OPTIONAL, sinceVersion, func(a pdf.Array) bool { return len(a) == 6 }) + if err != nil { + return err + } + + d1, err := validateDictEntry(xRefTable, d, dictName, "ExtGState", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateExtGStateDict(xRefTable, d1) + if err != nil { + return err + } + } + + // Shading: required, dict or stream dict. + o, ok := d.Find("Shading") + if !ok { + return errors.Errorf("pdfcpu: validateShadingPatternDict: missing required entry \"Shading\".") + } + + return validateShading(xRefTable, o) +} + +func validatePattern(xRefTable *pdf.XRefTable, o pdf.Object) error { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Dict: + err = validateShadingPatternDict(xRefTable, o, pdf.V13) + + case pdf.StreamDict: + err = validateTilingPatternDict(xRefTable, &o, pdf.V10) + + default: + err = errors.New("pdfcpu: validatePattern: corrupt obj typ, must be dict or stream dict") + + } + + return err +} + +func validatePatternResourceDict(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // see 8.7 Patterns + + // Version check + err := xRefTable.ValidateVersion("PatternResourceDict", sinceVersion) + if err != nil { + return err + } + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + // Iterate over pattern resource dictionary + for _, o := range d { + + // Process pattern + err = validatePattern(xRefTable, o) + if err != nil { + return err + } + + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/properties.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/properties.go new file mode 100644 index 0000000..924567c --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/properties.go @@ -0,0 +1,128 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + "github.com/pdfcpu/pdfcpu/pkg/log" + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validatePropertiesDict(xRefTable *pdf.XRefTable, o pdf.Object) error { + + // see 14.6.2 + // a dictionary containing private information meaningful to the conforming writer creating marked content. + + // anything possible + + + // empty dict ok + // Optional Metadata entry ok + // Optional Contents entry ok + // Optional Resources entry ok + + // Optional content group /OCG see 8.11.2 + // Optional content membership dict. /OCMD see 8.11.2.2 + // Optional MCID integer entry + // Optional Alt since 1.5 see 14.9.3 + // Optional ActualText since 1.5 see 14.9.4 + // Optional E see since 1.4 14.9.5 + // Optional Lang string RFC 3066 see 14.9.2 + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + err = validateMetadata(xRefTable, d, OPTIONAL, pdf.V14) + if err != nil { + return err + } + + for key, val := range d { + + log.Validate.Printf("validatePropertiesDict: key=%s val=%v\n", key, val) + + switch key { + + case "Metadata": + log.Validate.Printf("validatePropertiesDict: recognized key \"%s\"\n", key) + // see above + + case "Contents": + log.Validate.Printf("validatePropertiesDict: recognized key \"%s\"\n", key) + _, err = validateStreamDict(xRefTable, val) + if err != nil { + return err + } + + case "Resources": + log.Validate.Printf("validatePropertiesDict: recognized key \"%s\"\n", key) + _, err = validateResourceDict(xRefTable, val) + if err != nil { + return err + } + + case "OCG": + return errors.Errorf("validatePropertiesDict: recognized unsupported key \"%s\"\n", key) + + case "OCMD": + return errors.Errorf("validatePropertiesDict: recognized unsupported key \"%s\"\n", key) + + //case "MCID": -> default + //case "Alt": -> default + //case "ActualText": -> default + //case "E": -> default + //case "Lang": -> default + + default: + log.Validate.Printf("validatePropertiesDict: processing unrecognized key \"%s\"\n", key) + _, err = xRefTable.Dereference(val) + if err != nil { + return err + } + } + + } + + return nil +} + +func validatePropertiesResourceDict(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // Version check + err := xRefTable.ValidateVersion("PropertiesResourceDict", sinceVersion) + if err != nil { + return err + } + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + // Iterate over properties resource dict + for _, o := range d { + + // Process propDict + err = validatePropertiesDict(xRefTable, o) + if err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/shading.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/shading.go new file mode 100644 index 0000000..2b5478d --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/shading.go @@ -0,0 +1,351 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateBitsPerComponent(i int) bool { + return pdf.IntMemberOf(i, []int{1, 2, 4, 8, 12, 16}) +} + +func validateBitsPerCoordinate(i int) bool { + return pdf.IntMemberOf(i, []int{1, 2, 4, 8, 12, 16, 24, 32}) +} + +func validateShadingDictCommonEntries(xRefTable *pdf.XRefTable, dict pdf.Dict) (shadType int, err error) { + + dictName := "shadingDictCommonEntries" + + shadingType, err := validateIntegerEntry(xRefTable, dict, dictName, "ShadingType", REQUIRED, pdf.V10, func(i int) bool { return i >= 1 && i <= 7 }) + if err != nil { + return 0, err + } + + err = validateColorSpaceEntry(xRefTable, dict, dictName, "ColorSpace", OPTIONAL, ExcludePatternCS) + if err != nil { + return 0, err + } + + _, err = validateArrayEntry(xRefTable, dict, dictName, "Background", OPTIONAL, pdf.V10, nil) + if err != nil { + return 0, err + } + + _, err = validateRectangleEntry(xRefTable, dict, dictName, "BBox", OPTIONAL, pdf.V10, nil) + if err != nil { + return 0, err + } + + _, err = validateBooleanEntry(xRefTable, dict, dictName, "AntiAlias", OPTIONAL, pdf.V10, nil) + + return shadingType.Value(), err +} + +func validateFunctionBasedShadingDict(xRefTable *pdf.XRefTable, dict pdf.Dict) error { + + dictName := "functionBasedShadingDict" + + _, err := validateNumberArrayEntry(xRefTable, dict, dictName, "Domain", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 4 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, dict, dictName, "Matrix", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 6 }) + if err != nil { + return err + } + + return validateFunctionOrArrayOfFunctionsEntry(xRefTable, dict, dictName, "Function", REQUIRED, pdf.V10) +} + +func validateAxialShadingDict(xRefTable *pdf.XRefTable, dict pdf.Dict) error { + + dictName := "axialShadingDict" + + _, err := validateNumberArrayEntry(xRefTable, dict, dictName, "Coords", REQUIRED, pdf.V10, func(a pdf.Array) bool { return len(a) == 4 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, dict, dictName, "Domain", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + err = validateFunctionOrArrayOfFunctionsEntry(xRefTable, dict, dictName, "Function", REQUIRED, pdf.V10) + if err != nil { + return err + } + + _, err = validateBooleanArrayEntry(xRefTable, dict, dictName, "Extend", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + + return err +} + +func validateRadialShadingDict(xRefTable *pdf.XRefTable, dict pdf.Dict) error { + + dictName := "radialShadingDict" + + _, err := validateNumberArrayEntry(xRefTable, dict, dictName, "Coords", REQUIRED, pdf.V10, func(a pdf.Array) bool { return len(a) == 6 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, dict, dictName, "Domain", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + err = validateFunctionOrArrayOfFunctionsEntry(xRefTable, dict, dictName, "Function", REQUIRED, pdf.V10) + if err != nil { + return err + } + + _, err = validateBooleanArrayEntry(xRefTable, dict, dictName, "Extend", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + + return err +} + +func validateShadingDict(xRefTable *pdf.XRefTable, dict pdf.Dict) error { + + // Shading 1-3 + + shadingType, err := validateShadingDictCommonEntries(xRefTable, dict) + if err != nil { + return err + } + + switch shadingType { + case 1: + err = validateFunctionBasedShadingDict(xRefTable, dict) + + case 2: + err = validateAxialShadingDict(xRefTable, dict) + + case 3: + err = validateRadialShadingDict(xRefTable, dict) + + default: + return errors.Errorf("validateShadingDict: unexpected shadingType: %d\n", shadingType) + } + + return err +} + +func validateFreeFormGouroudShadedTriangleMeshesDict(xRefTable *pdf.XRefTable, dict pdf.Dict) error { + + dictName := "freeFormGouraudShadedTriangleMeshesDict" + + _, err := validateIntegerEntry(xRefTable, dict, dictName, "BitsPerCoordinate", REQUIRED, pdf.V10, validateBitsPerCoordinate) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, dict, dictName, "BitsPerComponent", REQUIRED, pdf.V10, validateBitsPerComponent) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, dict, dictName, "BitsPerFlag", REQUIRED, pdf.V10, func(i int) bool { return i >= 0 && i <= 2 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, dict, dictName, "Decode", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + return validateFunctionOrArrayOfFunctionsEntry(xRefTable, dict, dictName, "Function", OPTIONAL, pdf.V10) +} + +func validateLatticeFormGouraudShadedTriangleMeshesDict(xRefTable *pdf.XRefTable, dict pdf.Dict) error { + + dictName := "latticeFormGouraudShadedTriangleMeshesDict" + + _, err := validateIntegerEntry(xRefTable, dict, dictName, "BitsPerCoordinate", REQUIRED, pdf.V10, validateBitsPerCoordinate) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, dict, dictName, "BitsPerComponent", REQUIRED, pdf.V10, validateBitsPerComponent) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, dict, dictName, "VerticesPerRow", REQUIRED, pdf.V10, func(i int) bool { return i >= 2 }) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, dict, dictName, "Decode", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + return validateFunctionOrArrayOfFunctionsEntry(xRefTable, dict, dictName, "Function", OPTIONAL, pdf.V10) +} + +func validateCoonsPatchMeshesDict(xRefTable *pdf.XRefTable, dict pdf.Dict) error { + + dictName := "coonsPatchMeshesDict" + + _, err := validateIntegerEntry(xRefTable, dict, dictName, "BitsPerCoordinate", REQUIRED, pdf.V10, validateBitsPerCoordinate) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, dict, dictName, "BitsPerComponent", REQUIRED, pdf.V10, validateBitsPerComponent) + if err != nil { + return err + } + + validateBitsPerFlag := func(i int) bool { return i >= 0 && i <= 3 } + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + validateBitsPerFlag = func(i int) bool { return i >= 0 && i <= 8 } + } + _, err = validateIntegerEntry(xRefTable, dict, dictName, "BitsPerFlag", REQUIRED, pdf.V10, validateBitsPerFlag) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, dict, dictName, "Decode", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + return validateFunctionOrArrayOfFunctionsEntry(xRefTable, dict, dictName, "Function", OPTIONAL, pdf.V10) +} + +func validateTensorProductPatchMeshesDict(xRefTable *pdf.XRefTable, dict pdf.Dict) error { + + dictName := "tensorProductPatchMeshesDict" + + _, err := validateIntegerEntry(xRefTable, dict, dictName, "BitsPerCoordinate", REQUIRED, pdf.V10, validateBitsPerCoordinate) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, dict, dictName, "BitsPerComponent", REQUIRED, pdf.V10, validateBitsPerComponent) + if err != nil { + return err + } + + validateBitsPerFlag := func(i int) bool { return i >= 0 && i <= 3 } + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + validateBitsPerFlag = func(i int) bool { return i >= 0 && i <= 8 } + } + _, err = validateIntegerEntry(xRefTable, dict, dictName, "BitsPerFlag", REQUIRED, pdf.V10, validateBitsPerFlag) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, dict, dictName, "Decode", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + return validateFunctionOrArrayOfFunctionsEntry(xRefTable, dict, dictName, "Function", OPTIONAL, pdf.V10) +} + +func validateShadingStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict) error { + + // Shading 4-7 + + dict := sd.Dict + + shadingType, err := validateShadingDictCommonEntries(xRefTable, dict) + if err != nil { + return err + } + + switch shadingType { + + case 4: + err = validateFreeFormGouroudShadedTriangleMeshesDict(xRefTable, dict) + + case 5: + err = validateLatticeFormGouraudShadedTriangleMeshesDict(xRefTable, dict) + + case 6: + err = validateCoonsPatchMeshesDict(xRefTable, dict) + + case 7: + err = validateTensorProductPatchMeshesDict(xRefTable, dict) + + default: + return errors.Errorf("pdfcpu: validateShadingStreamDict: unexpected shadingType: %d\n", shadingType) + } + + return err +} + +func validateShading(xRefTable *pdf.XRefTable, obj pdf.Object) error { + + // see 8.7.4.3 Shading Dictionaries + + obj, err := xRefTable.Dereference(obj) + if err != nil || obj == nil { + return err + } + + switch obj := obj.(type) { + + case pdf.Dict: + err = validateShadingDict(xRefTable, obj) + + case pdf.StreamDict: + err = validateShadingStreamDict(xRefTable, &obj) + + default: + return errors.New("pdfcpu: validateShading: corrupt obj typ, must be dict or stream dict") + + } + + return err +} + +func validateShadingResourceDict(xRefTable *pdf.XRefTable, obj pdf.Object, sinceVersion pdf.Version) error { + + // see 8.7.4.3 Shading Dictionaries + + // Version check + err := xRefTable.ValidateVersion("shadingResourceDict", sinceVersion) + if err != nil { + return err + } + + d, err := xRefTable.DereferenceDict(obj) + if err != nil || d == nil { + return err + } + + // Iterate over shading resource dictionary + for _, obj := range d { + + // Process shading + err = validateShading(xRefTable, obj) + if err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/structTree.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/structTree.go new file mode 100644 index 0000000..b96b11a --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/structTree.go @@ -0,0 +1,688 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateMarkedContentReferenceDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + var err error + + // Pg: optional, indirect reference + // Page object representing a page on which the graphics object in the marked-content sequence shall be rendered. + if ir := d.IndirectRefEntry("Pg"); ir != nil { + err = processStructElementDictPgEntry(xRefTable, *ir) + if err != nil { + return err + } + } + + // Stm: optional, indirect reference + // The content stream containing the marked-content sequence. + if ir := d.IndirectRefEntry("Stm"); ir != nil { + _, err = xRefTable.Dereference(ir) + if err != nil { + return err + } + } + + // StmOwn: optional, indirect reference + // The PDF object owning the stream identified by Stems annotation to which an appearance stream belongs. + if ir := d.IndirectRefEntry("StmOwn"); ir != nil { + _, err = xRefTable.Dereference(ir) + if err != nil { + return err + } + } + + // MCID: required, integer + // The marked-content identifier of the marked-content sequence within its content stream. + + if d.IntEntry("MCID") == nil { + err = errors.Errorf("pdfcpu: validateMarkedContentReferenceDict: missing entry \"MCID\".") + } + + // if o, found := d.Find("MCID"); !found { + // // TODO FIX! + // } else { + // o, err := xRefTable.Dereference(o) + // if err != nil { + // return err + // } + + // if o == nil { + // return errors.Errorf("validateMarkedContentReferenceDict: missing entry \"MCID\".") + // } + // } + + return err +} + +func validateObjectReferenceDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // Pg: optional, indirect reference + // Page object representing a page on which some or all of the content items designated by the K entry shall be rendered. + if ir := d.IndirectRefEntry("Pg"); ir != nil { + err := processStructElementDictPgEntry(xRefTable, *ir) + if err != nil { + return err + } + } + + // Obj: required, indirect reference + ir := d.IndirectRefEntry("Obj") + if xRefTable.ValidationMode == pdf.ValidationStrict && ir == nil { + return errors.New("pdfcpu: validateObjectReferenceDict: missing required entry \"Obj\"") + } + + if ir == nil { + return nil + } + + obj, err := xRefTable.Dereference(*ir) + if err != nil { + return err + } + + if obj == nil { + return errors.New("pdfcpu: validateObjectReferenceDict: missing required entry \"Obj\"") + } + + return nil +} + +func validateStructElementDictEntryKArray(xRefTable *pdf.XRefTable, a pdf.Array) error { + + for _, o := range a { + + o, err := xRefTable.Dereference(o) + if err != nil { + return err + } + + if o == nil { + continue + } + + switch o := o.(type) { + + case pdf.Integer: + + case pdf.Dict: + + dictType := o.Type() + + if dictType == nil || *dictType == "StructElem" { + err = validateStructElementDict(xRefTable, o) + if err != nil { + return err + } + break + } + + if *dictType == "MCR" { + err = validateMarkedContentReferenceDict(xRefTable, o) + if err != nil { + return err + } + break + } + + if *dictType == "OBJR" { + err = validateObjectReferenceDict(xRefTable, o) + if err != nil { + return err + } + break + } + + return errors.Errorf("validateStructElementDictEntryKArray: invalid dictType %s (should be \"StructElem\" or \"OBJR\" or \"MCR\")\n", *dictType) + + default: + return errors.New("validateStructElementDictEntryKArray: unsupported PDF object") + + } + } + + return nil +} + +func validateStructElementDictEntryK(xRefTable *pdf.XRefTable, o pdf.Object) error { + + // K: optional, the children of this structure element + // + // struct element dict + // marked content reference dict + // object reference dict + // marked content id int + // array of all above + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Integer: + + case pdf.Dict: + + dictType := o.Type() + + if dictType == nil || *dictType == "StructElem" { + err = validateStructElementDict(xRefTable, o) + if err != nil { + return err + } + break + } + + if *dictType == "MCR" { + err = validateMarkedContentReferenceDict(xRefTable, o) + if err != nil { + return err + } + break + } + + if *dictType == "OBJR" { + err = validateObjectReferenceDict(xRefTable, o) + if err != nil { + return err + } + break + } + + return errors.Errorf("pdfcpu: validateStructElementDictEntryK: invalid dictType %s (should be \"StructElem\" or \"OBJR\" or \"MCR\")\n", *dictType) + + case pdf.Array: + + err = validateStructElementDictEntryKArray(xRefTable, o) + if err != nil { + return err + } + + default: + return errors.New("pdfcpu: validateStructElementDictEntryK: unsupported PDF object") + + } + + return nil +} + +func processStructElementDictPgEntry(xRefTable *pdf.XRefTable, ir pdf.IndirectRef) error { + + // is this object a known page object? + + o, err := xRefTable.Dereference(ir) + if err != nil { + return errors.Errorf("pdfcpu: processStructElementDictPgEntry: Pg obj:#%d gen:%d unknown\n", ir.ObjectNumber, ir.GenerationNumber) + } + + //logInfoWriter.Printf("known object for Pg: %v %s\n", obj, obj) + + if xRefTable.ValidationMode == pdf.ValidationRelaxed && o == nil { + return nil + } + + pageDict, ok := o.(pdf.Dict) + if !ok { + return errors.Errorf("pdfcpu: processStructElementDictPgEntry: Pg object corrupt dict: %s\n", o) + } + + if t := pageDict.Type(); t == nil || *t != "Page" { + return errors.Errorf("pdfcpu: processStructElementDictPgEntry: Pg object no pageDict: %s\n", pageDict) + } + + return nil +} + +func validateStructElementDictEntryA(xRefTable *pdf.XRefTable, o pdf.Object) error { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Dict: // No further processing. + + case pdf.StreamDict: // No further processing. + + case pdf.Array: + + for _, o := range o { + + o, err := xRefTable.Dereference(o) + if err != nil { + return err + } + + if o == nil { + continue + } + + switch o.(type) { + + case pdf.Integer: + // Each array element may be followed by a revision number (int).sort + + case pdf.Dict: + // No further processing. + + case pdf.StreamDict: + // No further processing. + + default: + return errors.Errorf("pdfcpu: validateStructElementDictEntryA: unsupported PDF object: %v\n.", o) + } + } + + default: + return errors.Errorf("pdfcpu: validateStructElementDictEntryA: unsupported PDF object: %v\n.", o) + + } + + return nil +} + +func validateStructElementDictEntryC(xRefTable *pdf.XRefTable, o pdf.Object) error { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + // No further processing. + + case pdf.Array: + + for _, o := range o { + + o, err := xRefTable.Dereference(o) + if err != nil { + return err + } + + if o == nil { + continue + } + + switch o.(type) { + + case pdf.Name: + // No further processing. + + case pdf.Integer: + // Each array element may be followed by a revision number. + + default: + return errors.New("pdfcpu: validateStructElementDictEntryC: unsupported PDF object") + + } + } + + default: + return errors.New("pdfcpu: validateStructElementDictEntryC: unsupported PDF object") + + } + + return nil +} + +func validateStructElementDictPart1(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // S: structure type, required, name, see 14.7.3 and Annex E. + _, err := validateNameEntry(xRefTable, d, dictName, "S", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // P: immediate parent, required, indirect reference + ir := d.IndirectRefEntry("P") + if xRefTable.ValidationMode != pdf.ValidationRelaxed { + if ir == nil { + return errors.Errorf("pdfcpu: validateStructElementDict: missing entry P: %s\n", d) + } + + // Check if parent structure element exists. + if _, ok := xRefTable.FindTableEntryForIndRef(ir); !ok { + return errors.Errorf("pdfcpu: validateStructElementDict: unknown parent: %v\n", ir) + } + } + + // ID: optional, byte string + _, err = validateStringEntry(xRefTable, d, dictName, "ID", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Pg: optional, indirect reference + // Page object representing a page on which some or all of the content items designated by the K entry shall be rendered. + if ir := d.IndirectRefEntry("Pg"); ir != nil { + err = processStructElementDictPgEntry(xRefTable, *ir) + if err != nil { + return err + } + } + + // K: optional, the children of this structure element. + if o, found := d.Find("K"); found { + err = validateStructElementDictEntryK(xRefTable, o) + if err != nil { + return err + } + } + + // A: optional, attribute objects: dict or stream dict or array of these. + if o, ok := d.Find("A"); ok { + err = validateStructElementDictEntryA(xRefTable, o) + } + + return err +} + +func validateStructElementDictPart2(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // C: optional, name or array + if o, ok := d.Find("C"); ok { + err := validateStructElementDictEntryC(xRefTable, o) + if err != nil { + return err + } + } + + // R: optional, integer >= 0 + _, err := validateIntegerEntry(xRefTable, d, dictName, "R", OPTIONAL, pdf.V10, func(i int) bool { return i >= 0 }) + if err != nil { + return err + } + + // T: optional, text string + _, err = validateStringEntry(xRefTable, d, dictName, "T", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Lang: optional, text string, since 1.4 + sinceVersion := pdf.V14 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + _, err = validateStringEntry(xRefTable, d, dictName, "Lang", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // Alt: optional, text string + _, err = validateStringEntry(xRefTable, d, dictName, "Alt", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // E: optional, text sttring, since 1.5 + _, err = validateStringEntry(xRefTable, d, dictName, "E", OPTIONAL, pdf.V15, nil) + if err != nil { + return err + } + + // ActualText: optional, text string, since 1.4 + _, err = validateStringEntry(xRefTable, d, dictName, "ActualText", OPTIONAL, pdf.V14, nil) + + return err +} + +func validateStructElementDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // See table 323 + + dictName := "StructElementDict" + + err := validateStructElementDictPart1(xRefTable, d, dictName) + if err != nil { + return err + } + + return validateStructElementDictPart2(xRefTable, d, dictName) +} + +func validateStructTreeRootDictEntryKArray(xRefTable *pdf.XRefTable, a pdf.Array) error { + + for _, o := range a { + + o, err := xRefTable.Dereference(o) + if err != nil { + return err + } + + if o == nil { + continue + } + + switch o := o.(type) { + + case pdf.Dict: + + dictType := o.Type() + + if dictType == nil || *dictType == "StructElem" { + err = validateStructElementDict(xRefTable, o) + if err != nil { + return err + } + break + } + + return errors.Errorf("pdfcpu: validateStructTreeRootDictEntryKArray: invalid dictType %s (should be \"StructElem\")\n", *dictType) + + default: + return errors.New("pdfcpu: validateStructTreeRootDictEntryKArray: unsupported PDF object") + + } + } + + return nil +} + +func validateStructTreeRootDictEntryK(xRefTable *pdf.XRefTable, o pdf.Object) error { + + // The immediate child or children of the structure tree root in the structure hierarchy. + // The value may be either a dictionary representing a single structure element or an array of such dictionaries. + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Dict: + + dictType := o.Type() + + if dictType == nil || *dictType == "StructElem" { + err = validateStructElementDict(xRefTable, o) + if err != nil { + return err + } + break + } + + return errors.Errorf("validateStructTreeRootDictEntryK: invalid dictType %s (should be \"StructElem\")\n", *dictType) + + case pdf.Array: + + err = validateStructTreeRootDictEntryKArray(xRefTable, o) + if err != nil { + return err + } + + default: + return errors.New("pdfcpu: validateStructTreeRootDictEntryK: unsupported PDF object") + + } + + return nil +} + +func processStructTreeClassMapDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + for _, o := range d { + + // Process dict or array of dicts. + + o, err := xRefTable.Dereference(o) + if err != nil { + return err + } + + if o == nil { + continue + } + + switch o := o.(type) { + + case pdf.Dict: + // no further processing. + + case pdf.Array: + + for _, o := range o { + + _, err = xRefTable.DereferenceDict(o) + if err != nil { + return err + } + + } + + default: + return errors.New("pdfcpu: processStructTreeClassMapDict: unsupported PDF object") + + } + + } + + return nil +} + +func validateStructTreeRootDictEntryParentTree(xRefTable *pdf.XRefTable, ir *pdf.IndirectRef) error { + + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + + // Accept empty dict + d, err := xRefTable.DereferenceDict(*ir) + if err != nil { + return err + } + if d == nil || d.Len() == 0 { + return nil + } + } + + _, _, err := validateNumberTree(xRefTable, "StructTree", *ir, true) + return err +} + +func validateStructTreeRootDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "StructTreeRootDict" + + // required entry Type: name:StructTreeRoot + if d.Type() == nil || *d.Type() != "StructTreeRoot" { + return errors.New("pdfcpu: validateStructTreeRootDict: missing type") + } + + // Optional entry K: struct element dict or array of struct element dicts + if o, found := d.Find("K"); found { + err := validateStructTreeRootDictEntryK(xRefTable, o) + if err != nil { + return err + } + } + + // Optional entry IDTree: name tree, key=elementId value=struct element dict + // A name tree that maps element identifiers to the structure elements they denote. + ir := d.IndirectRefEntry("IDTree") + if ir != nil { + d, err := xRefTable.DereferenceDict(*ir) + if err != nil { + return err + } + _, _, _, err = validateNameTree(xRefTable, "IDTree", d, true) + if err != nil { + return err + } + } + + // Optional entry ParentTree: number tree, value=indRef of struct element dict or array of struct element dicts + // A number tree used in finding the structure elements to which content items belong. + if ir = d.IndirectRefEntry("ParentTree"); ir != nil { + err := validateStructTreeRootDictEntryParentTree(xRefTable, ir) + if err != nil { + return err + } + } + + // Optional entry ParentTreeNextKey: integer + _, err := validateIntegerEntry(xRefTable, d, dictName, "ParentTreeNextKey", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Optional entry RoleMap: dict + // A dictionary that shall map the names of structure used in the document + // to their approximate equivalents in the set of standard structure + _, err = validateDictEntry(xRefTable, d, dictName, "RoleMap", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Optional entry ClassMap: dict + // A dictionary that shall map name objects designating attribute classes + // to the corresponding attribute objects or arrays of attribute objects. + d1, err := validateDictEntry(xRefTable, d, dictName, "ClassMap", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + if d1 != nil { + err = processStructTreeClassMapDict(xRefTable, d1) + } + + return err +} + +func validateStructTree(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // 14.7.2 Structure Hierarchy + + d, err := validateDictEntry(xRefTable, rootDict, "RootDict", "StructTreeRoot", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + return validateStructTreeRootDict(xRefTable, d) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/thread.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/thread.go new file mode 100644 index 0000000..88b077b --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/thread.go @@ -0,0 +1,249 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +func validateEntryV(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, required bool, sinceVersion pdf.Version, pBeadIndRef *pdf.IndirectRef, objNumber int) error { + + previousBeadIndRef, err := validateIndRefEntry(xRefTable, d, dictName, "V", required, sinceVersion) + if err != nil { + return err + } + + if !previousBeadIndRef.Equals(*pBeadIndRef) { + return errors.Errorf("pdfcpu: validateEntryV: obj#%d invalid entry V, corrupt previous Bead indirect reference", objNumber) + } + + return nil +} + +func validateBeadDict(xRefTable *pdf.XRefTable, beadIndRef, threadIndRef, pBeadIndRef, lBeadIndRef *pdf.IndirectRef) error { + + objNumber := beadIndRef.ObjectNumber.Value() + + dictName := "beadDict" + sinceVersion := pdf.V10 + + d, err := xRefTable.DereferenceDict(*beadIndRef) + if err != nil { + return err + } + if d == nil { + return errors.Errorf("pdfcpu: validateBeadDict: obj#%d missing dict", objNumber) + } + + // Validate optional entry Type, must be "Bead". + _, err = validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Bead" }) + if err != nil { + return err + } + + // Validate entry T, must refer to threadDict. + indRefT, err := validateIndRefEntry(xRefTable, d, dictName, "T", OPTIONAL, sinceVersion) + if err != nil { + return err + } + if indRefT != nil && !indRefT.Equals(*threadIndRef) { + return errors.Errorf("pdfcpu: validateBeadDict: obj#%d invalid entry T (backpointer to ThreadDict)", objNumber) + } + + // Validate required entry R, must be rectangle. + _, err = validateRectangleEntry(xRefTable, d, dictName, "R", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + // Validate required entry P, must be indRef to pageDict. + err = validateEntryP(xRefTable, d, dictName, REQUIRED, sinceVersion) + if err != nil { + return err + } + + // Validate required entry V, must refer to previous bead. + err = validateEntryV(xRefTable, d, dictName, REQUIRED, sinceVersion, pBeadIndRef, objNumber) + if err != nil { + return err + } + + // Validate required entry N, must refer to last bead. + nBeadIndRef, err := validateIndRefEntry(xRefTable, d, dictName, "N", REQUIRED, sinceVersion) + if err != nil { + return err + } + + // Recurse until next bead equals last bead. + if !nBeadIndRef.Equals(*lBeadIndRef) { + err = validateBeadDict(xRefTable, nBeadIndRef, threadIndRef, beadIndRef, lBeadIndRef) + if err != nil { + return err + } + } + + return nil +} + +func soleBeadDict(beadIndRef, pBeadIndRef, nBeadIndRef *pdf.IndirectRef) bool { + // if N and V reference this bead dict, must be the first and only one. + return pBeadIndRef.Equals(*nBeadIndRef) && beadIndRef.Equals(*pBeadIndRef) +} + +func validateBeadChainIntegrity(beadIndRef, pBeadIndRef, nBeadIndRef *pdf.IndirectRef) bool { + return !pBeadIndRef.Equals(*beadIndRef) && !nBeadIndRef.Equals(*beadIndRef) +} + +func validateFirstBeadDict(xRefTable *pdf.XRefTable, beadIndRef, threadIndRef *pdf.IndirectRef) error { + + dictName := "firstBeadDict" + sinceVersion := pdf.V10 + + d, err := xRefTable.DereferenceDict(*beadIndRef) + if err != nil { + return err + } + + if d == nil { + return errors.New("pdfcpu: validateFirstBeadDict: missing dict") + } + + _, err = validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Bead" }) + if err != nil { + return err + } + + indRefT, err := validateIndRefEntry(xRefTable, d, dictName, "T", REQUIRED, sinceVersion) + if err != nil { + return err + } + + if !indRefT.Equals(*threadIndRef) { + return errors.New("pdfcpu: validateFirstBeadDict: invalid entry T (backpointer to ThreadDict)") + } + + _, err = validateRectangleEntry(xRefTable, d, dictName, "R", REQUIRED, sinceVersion, nil) + if err != nil { + return err + } + + err = validateEntryP(xRefTable, d, dictName, REQUIRED, sinceVersion) + if err != nil { + return err + } + + pBeadIndRef, err := validateIndRefEntry(xRefTable, d, dictName, "V", REQUIRED, sinceVersion) + if err != nil { + return err + } + + nBeadIndRef, err := validateIndRefEntry(xRefTable, d, dictName, "N", REQUIRED, sinceVersion) + if err != nil { + return err + } + + if soleBeadDict(beadIndRef, pBeadIndRef, nBeadIndRef) { + return nil + } + + if !validateBeadChainIntegrity(beadIndRef, pBeadIndRef, nBeadIndRef) { + return errors.New("pdfcpu: validateFirstBeadDict: corrupt chain of beads") + } + + return validateBeadDict(xRefTable, nBeadIndRef, threadIndRef, beadIndRef, pBeadIndRef) +} + +func validateThreadDict(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + dictName := "threadDict" + + threadIndRef, ok := o.(pdf.IndirectRef) + if !ok { + return errors.New("pdfcpu: validateThreadDict: not an indirect ref") + } + + objNumber := threadIndRef.ObjectNumber.Value() + + d, err := xRefTable.DereferenceDict(threadIndRef) + if err != nil { + return err + } + + _, err = validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Thread" }) + if err != nil { + return err + } + + // Validate optional thread information dict entry. + o, found := d.Find("I") + if found && o != nil { + _, err = validateDocumentInfoDict(xRefTable, o) + if err != nil { + return err + } + } + + fBeadIndRef := d.IndirectRefEntry("F") + if fBeadIndRef == nil { + return errors.Errorf("pdfcpu: validateThreadDict: obj#%d required indirect entry \"F\" missing", objNumber) + } + + // Validate the list of beads starting with the first bead dict. + return validateFirstBeadDict(xRefTable, fBeadIndRef, &threadIndRef) +} + +func validateThreads(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 12.4.3 Articles + + ir := rootDict.IndirectRefEntry("Threads") + if ir == nil { + if required { + return errors.New("pdfcpu: validateThreads: required entry \"Threads\" missing") + } + return nil + } + + a, err := xRefTable.DereferenceArray(*ir) + if err != nil { + return err + } + if a == nil { + return nil + } + + err = xRefTable.ValidateVersion("threads", sinceVersion) + if err != nil { + return err + } + + for _, o := range a { + + if o == nil { + continue + } + + err = validateThreadDict(xRefTable, o, sinceVersion) + if err != nil { + return err + } + + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/xObject.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/xObject.go new file mode 100644 index 0000000..2bfd196 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/xObject.go @@ -0,0 +1,872 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + "github.com/pdfcpu/pdfcpu/pkg/filter" + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +const ( + + // ExcludePatternCS ... + ExcludePatternCS = true + + // IncludePatternCS ... + IncludePatternCS = false + + isAlternateImageStreamDict = true + isNoAlternateImageStreamDict = false +) + +func validateReferenceDictPageEntry(xRefTable *pdf.XRefTable, o pdf.Object) error { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o.(type) { + + case pdf.Integer, pdf.StringLiteral, pdf.HexLiteral: + // no further processing + + default: + return errors.New("pdfcpu: validateReferenceDictPageEntry: corrupt type") + + } + + return nil +} + +func validateReferenceDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // see 8.10.4 Reference XObjects + + dictName := "refDict" + + // F, file spec, required + _, err := validateFileSpecEntry(xRefTable, d, dictName, "F", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // Page, integer or text string, required + o, ok := d.Find("Page") + if !ok { + return errors.New("pdfcpu: validateReferenceDict: missing required entry \"Page\"") + } + + err = validateReferenceDictPageEntry(xRefTable, o) + if err != nil { + return err + } + + // ID, string array, optional + _, err = validateStringArrayEntry(xRefTable, d, dictName, "ID", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + + return err +} + +func validateOPIDictV13Part1(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "OPI" }) + if err != nil { + return err + } + + // Version, required, number + _, err = validateNumberEntry(xRefTable, d, dictName, "Version", REQUIRED, pdf.V10, func(f float64) bool { return f == 1.3 }) + if err != nil { + return err + } + + // F, required, file specification + _, err = validateFileSpecEntry(xRefTable, d, dictName, "F", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // ID, optional, byte string + _, err = validateStringEntry(xRefTable, d, dictName, "ID", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Comments, optional, text string + _, err = validateStringEntry(xRefTable, d, dictName, "Comments", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Size, required, array of integers, len 2 + _, err = validateIntegerArrayEntry(xRefTable, d, dictName, "Size", REQUIRED, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + // CropRect, required, array of integers, len 4 + _, err = validateRectangleEntry(xRefTable, d, dictName, "CropRect", REQUIRED, pdf.V10, nil) + + if err != nil { + return err + } + + // CropFixed, optional, array of numbers, len 4 + _, err = validateRectangleEntry(xRefTable, d, dictName, "CropFixed", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Position, required, array of numbers, len 8 + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Position", REQUIRED, pdf.V10, func(a pdf.Array) bool { return len(a) == 8 }) + + return err +} + +func validateOPIDictV13Part2(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // Resolution, optional, array of numbers, len 2 + _, err := validateNumberArrayEntry(xRefTable, d, dictName, "Resolution", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + // ColorType, optional, name + _, err = validateNameEntry(xRefTable, d, dictName, "ColorType", OPTIONAL, pdf.V10, func(s string) bool { return s == "Process" || s == "Spot" || s == "Separation" }) + if err != nil { + return err + } + + // Color, optional, array, len 5 + _, err = validateArrayEntry(xRefTable, d, dictName, "Color", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 5 }) + if err != nil { + return err + } + + // Tint, optional, number + _, err = validateNumberEntry(xRefTable, d, dictName, "Tint", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Overprint, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "Overprint", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // ImageType, optional, array of integers, len 2 + _, err = validateIntegerArrayEntry(xRefTable, d, dictName, "ImageType", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + // GrayMap, optional, array of integers + _, err = validateIntegerArrayEntry(xRefTable, d, dictName, "GrayMap", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Transparency, optional, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "Transparency", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Tags, optional, array + _, err = validateArrayEntry(xRefTable, d, dictName, "Tags", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateOPIDictV13(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // 14.11.7 Open Prepresse interface (OPI) + + dictName := "opiDictV13" + + err := validateOPIDictV13Part1(xRefTable, d, dictName) + if err != nil { + return err + } + + return validateOPIDictV13Part2(xRefTable, d, dictName) +} + +func validateOPIDictInks(xRefTable *pdf.XRefTable, o pdf.Object) error { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Name: + if colorant := o.Value(); colorant != "full_color" && colorant != "registration" { + return errors.New("pdfcpu: validateOPIDictInks: corrupt colorant name") + } + + case pdf.Array: + // no further processing + + default: + return errors.New("pdfcpu: validateOPIDictInks: corrupt type") + + } + + return nil +} + +func validateOPIDictV20(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // 14.11.7 Open Prepresse interface (OPI) + + dictName := "opiDictV20" + + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "OPI" }) + if err != nil { + return err + } + + _, err = validateNumberEntry(xRefTable, d, dictName, "Version", REQUIRED, pdf.V10, func(f float64) bool { return f == 2.0 }) + if err != nil { + return err + } + + _, err = validateFileSpecEntry(xRefTable, d, dictName, "F", REQUIRED, pdf.V10) + if err != nil { + return err + } + + _, err = validateStringEntry(xRefTable, d, dictName, "MainImage", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateArrayEntry(xRefTable, d, dictName, "Tags", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Size", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + _, err = validateRectangleEntry(xRefTable, d, dictName, "CropRect", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateBooleanEntry(xRefTable, d, dictName, "Overprint", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + if o, found := d.Find("Inks"); found { + err = validateOPIDictInks(xRefTable, o) + if err != nil { + return err + } + } + + _, err = validateIntegerArrayEntry(xRefTable, d, dictName, "IncludedImageDimensions", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 2 }) + if err != nil { + return err + } + + _, err = validateIntegerEntry(xRefTable, d, dictName, "IncludedImageQuality", OPTIONAL, pdf.V10, func(i int) bool { return i >= 1 && i <= 3 }) + + return err +} + +func validateOPIVersionDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + // 14.11.7 Open Prepresse interface (OPI) + + if d.Len() != 1 { + return errors.New("pdfcpu: validateOPIVersionDict: must have exactly one entry keyed 1.3 or 2.0") + } + + validateOPIVersion := func(s string) bool { return pdf.MemberOf(s, []string{"1.3", "2.0"}) } + + for opiVersion, obj := range d { + + if !validateOPIVersion(opiVersion) { + return errors.New("pdfcpu: validateOPIVersionDict: invalid OPI version") + } + + d, err := xRefTable.DereferenceDict(obj) + if err != nil || d == nil { + return err + } + + if opiVersion == "1.3" { + err = validateOPIDictV13(xRefTable, d) + } else { + err = validateOPIDictV20(xRefTable, d) + } + + if err != nil { + return err + } + + } + + return nil +} + +func validateMaskStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict) error { + + if sd.Type() != nil && *sd.Type() != "XObject" { + return errors.New("pdfcpu: validateMaskStreamDict: corrupt imageStreamDict type") + } + + if sd.Subtype() == nil || *sd.Subtype() != "Image" { + return errors.New("pdfcpu: validateMaskStreamDict: corrupt imageStreamDict subtype") + } + + return validateImageStreamDict(xRefTable, sd, isNoAlternateImageStreamDict) +} + +func validateMaskEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + // stream ("explicit masking", another Image XObject) or array of colors ("color key masking") + + o, err := validateEntry(xRefTable, d, dictName, entryName, required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.StreamDict: + err = validateMaskStreamDict(xRefTable, &o) + if err != nil { + return err + } + + case pdf.Array: + // no further processing + + default: + + return errors.Errorf("pdfcpu: validateMaskEntry: dict=%s corrupt entry \"%s\"\n", dictName, entryName) + + } + + return nil +} + +func validateAlternateImageStreamDicts(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, entryName string, required bool, sinceVersion pdf.Version) error { + + a, err := validateArrayEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil { + return err + } + if a == nil { + if required { + return errors.Errorf("pdfcpu: validateAlternateImageStreamDicts: dict=%s required entry \"%s\" missing.", dictName, entryName) + } + return nil + } + + for _, o := range a { + + sd, err := validateStreamDict(xRefTable, o) + if err != nil { + return err + } + + if sd == nil { + continue + } + + err = validateImageStreamDict(xRefTable, sd, isAlternateImageStreamDict) + if err != nil { + return err + } + } + + return nil +} + +func validateImageStreamDictPart1(xRefTable *pdf.XRefTable, sd *pdf.StreamDict, dictName string) (isImageMask bool, err error) { + + // Width, integer, required + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "Width", REQUIRED, pdf.V10, nil) + if err != nil { + return false, err + } + + // Height, integer, required + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "Height", REQUIRED, pdf.V10, nil) + if err != nil { + return false, err + } + + // ImageMask, boolean, optional + imageMask, err := validateBooleanEntry(xRefTable, sd.Dict, dictName, "ImageMask", OPTIONAL, pdf.V10, nil) + if err != nil { + return false, err + } + + isImageMask = imageMask != nil && *imageMask == true + + // ColorSpace, name or array, required unless used filter is JPXDecode; not allowed for imagemasks. + if !isImageMask { + + required := REQUIRED + + if sd.HasSoleFilterNamed(filter.JPX) { + required = OPTIONAL + } + + if sd.HasSoleFilterNamed(filter.CCITTFax) && xRefTable.ValidationMode == pdf.ValidationRelaxed { + required = OPTIONAL + } + + err = validateColorSpaceEntry(xRefTable, sd.Dict, dictName, "ColorSpace", required, ExcludePatternCS) + if err != nil { + return false, err + } + + } + + return isImageMask, nil +} + +func validateImageStreamDictPart2(xRefTable *pdf.XRefTable, sd *pdf.StreamDict, dictName string, isImageMask, isAlternate bool) error { + + // BitsPerComponent, integer + required := REQUIRED + if sd.HasSoleFilterNamed(filter.JPX) || isImageMask { + required = OPTIONAL + } + // For imageMasks BitsPerComponent must be 1. + var validateBPC func(i int) bool + if isImageMask { + validateBPC = func(i int) bool { + return i == 1 + } + } + _, err := validateIntegerEntry(xRefTable, sd.Dict, dictName, "BitsPerComponent", required, pdf.V10, validateBPC) + if err != nil { + return err + } + + // Intent, name, optional, since V1.0 + validate := func(s string) bool { + return pdf.MemberOf(s, []string{"AbsoluteColorimetric", "RelativeColorimetric", "Saturation", "Perceptual"}) + } + _, err = validateNameEntry(xRefTable, sd.Dict, dictName, "Intent", OPTIONAL, pdf.V11, validate) + if err != nil { + return err + } + + // Mask, stream or array, optional since V1.3; not allowed for image masks. + if !isImageMask { + err = validateMaskEntry(xRefTable, sd.Dict, dictName, "Mask", OPTIONAL, pdf.V13) + if err != nil { + return err + } + } + + // Decode, array, optional + _, err = validateNumberArrayEntry(xRefTable, sd.Dict, dictName, "Decode", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Interpolate, boolean, optional + _, err = validateBooleanEntry(xRefTable, sd.Dict, dictName, "Interpolate", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Alternates, array, optional, since V1.3 + if !isAlternate { + err = validateAlternateImageStreamDicts(xRefTable, sd.Dict, dictName, "Alternates", OPTIONAL, pdf.V13) + } + + return err +} + +func validateImageStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict, isAlternate bool) error { + dictName := "imageStreamDict" + var isImageMask bool + + isImageMask, err := validateImageStreamDictPart1(xRefTable, sd, dictName) + if err != nil { + return err + } + + err = validateImageStreamDictPart2(xRefTable, sd, dictName, isImageMask, isAlternate) + if err != nil { + return err + } + + // SMask, stream, optional, since V1.4 + sinceVersion := pdf.V14 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + sd1, err := validateStreamDictEntry(xRefTable, sd.Dict, dictName, "SMask", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + if sd1 != nil { + err = validateImageStreamDict(xRefTable, sd1, isNoAlternateImageStreamDict) + if err != nil { + return err + } + } + + // SMaskInData, integer, optional + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "SMaskInData", OPTIONAL, pdf.V10, func(i int) bool { return i >= 0 && i <= 2 }) + if err != nil { + return err + } + + // Name, name, required for V10 + // Shall no longer be used. + // _, err = validateNameEntry(xRefTable, sd.Dict, dictName, "Name", xRefTable.Version() == pdf.V10, pdf.V10, nil) + // if err != nil { + // return err + // } + + // StructParent, integer, optional + _, err = validateIntegerEntry(xRefTable, sd.Dict, dictName, "StructParent", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // ID, byte string, optional, since V1.3 + _, err = validateStringEntry(xRefTable, sd.Dict, dictName, "ID", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // OPI, dict, optional since V1.2 + err = validateEntryOPI(xRefTable, sd.Dict, dictName, "OPI", OPTIONAL, pdf.V12) + if err != nil { + return err + } + + // Metadata, stream, optional since V1.4 + err = validateMetadata(xRefTable, sd.Dict, OPTIONAL, pdf.V14) + if err != nil { + return err + } + + // OC, dict, optional since V1.5 + return validateEntryOC(xRefTable, sd.Dict, dictName, "OC", OPTIONAL, pdf.V15) +} + +func validateFormStreamDictPart1(xRefTable *pdf.XRefTable, sd *pdf.StreamDict, dictName string) error { + + _, err := validateIntegerEntry(xRefTable, sd.Dict, dictName, "FormType", OPTIONAL, pdf.V10, func(i int) bool { return i == 1 }) + if err != nil { + return err + } + + _, err = validateRectangleEntry(xRefTable, sd.Dict, dictName, "BBox", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateNumberArrayEntry(xRefTable, sd.Dict, dictName, "Matrix", OPTIONAL, pdf.V10, func(a pdf.Array) bool { return len(a) == 6 }) + if err != nil { + return err + } + + // Resources, dict, optional, since V1.2 + if o, ok := sd.Find("Resources"); ok { + _, err = validateResourceDict(xRefTable, o) + if err != nil { + return err + } + } + + // Group, dict, optional, since V1.4 + err = validatePageEntryGroup(xRefTable, sd.Dict, OPTIONAL, pdf.V14) + if err != nil { + return err + } + + // Ref, dict, optional, since V1.4 + d, err := validateDictEntry(xRefTable, sd.Dict, dictName, "Ref", OPTIONAL, pdf.V14, nil) + if err != nil { + return err + } + if d != nil { + err = validateReferenceDict(xRefTable, d) + if err != nil { + return err + } + } + + // Metadata, stream, optional, since V1.4 + return validateMetadata(xRefTable, sd.Dict, OPTIONAL, pdf.V14) +} + +func validateEntryOC(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateOptionalContentGroupDict(xRefTable, d1, sinceVersion) + } + + return err +} + +func validateEntryOPI(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) error { + + d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil { + return err + } + + if d1 != nil { + err = validateOPIVersionDict(xRefTable, d1) + } + + return err +} + +func validateFormStreamDictPart2(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string) error { + + // PieceInfo, dict, optional, since V1.3 + hasPieceInfo, err := validatePieceInfo(xRefTable, d, dictName, "PieceInfo", OPTIONAL, pdf.V13) + if err != nil { + return err + } + + // LastModified, date, required if PieceInfo present, since V1.3 + lm, err := validateDateEntry(xRefTable, d, dictName, "LastModified", OPTIONAL, pdf.V13) + if err != nil { + return err + } + + if hasPieceInfo && lm == nil { + err = errors.New("pdfcpu: validateFormStreamDictPart2: missing \"LastModified\" (required by \"PieceInfo\")") + return err + } + + // StructParent, integer + sp, err := validateIntegerEntry(xRefTable, d, dictName, "StructParent", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + // StructParents, integer + sps, err := validateIntegerEntry(xRefTable, d, dictName, "StructParents", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + if sp != nil && sps != nil { + return errors.New("pdfcpu: validateFormStreamDictPart2: only \"StructParent\" or \"StructParents\" allowed") + } + + // OPI, dict, optional, since V1.2 + err = validateEntryOPI(xRefTable, d, dictName, "OPI", OPTIONAL, pdf.V12) + if err != nil { + return err + } + + // OC, optional, content group dict or content membership dict, since V1.5 + // Specifying the optional content properties for the annotation. + sinceVersion := pdf.V15 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + err = validateOptionalContent(xRefTable, d, dictName, "OC", OPTIONAL, sinceVersion) + if err != nil { + return err + } + + // Name, name, optional (required in 1.0) + required := xRefTable.Version() == pdf.V10 + _, err = validateNameEntry(xRefTable, d, dictName, "Name", required, pdf.V10, nil) + + return err +} + +func validateFormStreamDict(xRefTable *pdf.XRefTable, sd *pdf.StreamDict) error { + + // 8.10 Form XObjects + + dictName := "formStreamDict" + + err := validateFormStreamDictPart1(xRefTable, sd, dictName) + if err != nil { + return err + } + + return validateFormStreamDictPart2(xRefTable, sd.Dict, dictName) +} + +func validateXObjectType(xRefTable *pdf.XRefTable, sd *pdf.StreamDict) error { + ss := []string{"XObject"} + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + ss = append(ss, "Xobject") + } + + n, err := validateNameEntry(xRefTable, sd.Dict, "xObjectStreamDict", "Type", OPTIONAL, pdf.V10, func(s string) bool { return pdf.MemberOf(s, ss) }) + if err != nil { + return err + } + + // Repair "Xobject" to "XObject". + if n != nil && *n == "Xobject" { + sd.Dict["Type"] = pdf.Name("XObject") + } + + return nil +} + +func validateXObjectStreamDict(xRefTable *pdf.XRefTable, o pdf.Object) error { + + // see 8.8 External Objects + + // Dereference stream dict and ensure it is validated exactly once in order handle + // XObjects(forms) with recursive structures like produced by Microsoft. + sd, valid, err := xRefTable.DereferenceStreamDict(o) + if valid { + return nil + } + if err != nil || sd == nil { + return err + } + + dictName := "xObjectStreamDict" + + if err := validateXObjectType(xRefTable, sd); err != nil { + return err + } + + required := REQUIRED + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + required = OPTIONAL + } + subtype, err := validateNameEntry(xRefTable, sd.Dict, dictName, "Subtype", required, pdf.V10, nil) + if err != nil { + return err + } + + if subtype == nil { + + // relaxed + _, found := sd.Find("BBox") + if found { + return validateFormStreamDict(xRefTable, sd) + } + + // Relaxed for page Thumb + return validateImageStreamDict(xRefTable, sd, isNoAlternateImageStreamDict) + } + + switch *subtype { + + case "Form": + err = validateFormStreamDict(xRefTable, sd) + + case "Image": + err = validateImageStreamDict(xRefTable, sd, isNoAlternateImageStreamDict) + + case "PS": + err = errors.Errorf("pdfcpu: validateXObjectStreamDict: PostScript XObjects should not be used") + + default: + return errors.Errorf("pdfcpu: validateXObjectStreamDict: unknown Subtype: %s\n", *subtype) + + } + + return err +} + +func validateGroupAttributesDict(xRefTable *pdf.XRefTable, o pdf.Object) error { + + // see 11.6.6 Transparency Group XObjects + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + dictName := "groupAttributesDict" + + // Type, name, optional + _, err = validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "Group" }) + if err != nil { + return err + } + + // S, name, required + _, err = validateNameEntry(xRefTable, d, dictName, "S", REQUIRED, pdf.V10, func(s string) bool { return s == "Transparency" }) + if err != nil { + return err + } + + // CS, colorSpace, optional + err = validateColorSpaceEntry(xRefTable, d, dictName, "CS", OPTIONAL, ExcludePatternCS) + if err != nil { + return err + } + + // I, boolean, optional + _, err = validateBooleanEntry(xRefTable, d, dictName, "I", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateXObjectResourceDict(xRefTable *pdf.XRefTable, o pdf.Object, sinceVersion pdf.Version) error { + + // Version check + err := xRefTable.ValidateVersion("XObjectResourceDict", sinceVersion) + if err != nil { + return err + } + + d, err := xRefTable.DereferenceDict(o) + if err != nil || d == nil { + return err + } + + //fmt.Printf("XObjResDict:\n%s\n", d) + + // Iterate over XObject resource dictionary + for _, o := range d { + + // Process XObject dict + err = validateXObjectStreamDict(xRefTable, o) + if err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/xReftable.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/xReftable.go new file mode 100644 index 0000000..0ba1e27 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate/xReftable.go @@ -0,0 +1,919 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package validate implements validation against PDF 32000-1:2008. +package validate + +import ( + "github.com/pdfcpu/pdfcpu/pkg/log" + pdf "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" + "github.com/pkg/errors" +) + +// XRefTable validates a PDF cross reference table obeying the validation mode. +func XRefTable(xRefTable *pdf.XRefTable) error { + + log.Info.Println("validating") + log.Validate.Println("*** validateXRefTable begin ***") + + // Validate root object(aka the document catalog) and page tree. + err := validateRootObject(xRefTable) + if err != nil { + return err + } + + // Validate document information dictionary. + err = validateDocumentInfoObject(xRefTable) + if err != nil { + return err + } + + // Validate offspec additional streams as declared in pdf trailer. + err = validateAdditionalStreams(xRefTable) + if err != nil { + return err + } + + xRefTable.Valid = true + + log.Validate.Println("*** validateXRefTable end ***") + + return nil +} + +func validateRootVersion(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validateNameEntry(xRefTable, rootDict, "rootDict", "Version", OPTIONAL, sinceVersion, nil) + + return err +} + +func validateExtensions(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 7.12 Extensions Dictionary + + _, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Extensions", required, sinceVersion, nil) + + // No validation due to lack of documentation. + + return err +} + +func validatePageLabels(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // optional since PDF 1.3 + // => 7.9.7 Number Trees, 12.4.2 Page Labels + + // Dict or indirect ref to Dict + + ir := rootDict.IndirectRefEntry("PageLabels") + if ir == nil { + if required { + return errors.Errorf("validatePageLabels: required entry \"PageLabels\" missing") + } + return nil + } + + dictName := "PageLabels" + + // Version check + err := xRefTable.ValidateVersion(dictName, sinceVersion) + if err != nil { + return err + } + + _, _, err = validateNumberTree(xRefTable, "PageLabel", *ir, true) + + return err +} + +func validateNames(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 7.7.4 Name Dictionary + + d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Names", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + validateNameTreeName := func(s string) bool { + return pdf.MemberOf(s, []string{"Dests", "AP", "JavaScript", "Pages", "Templates", "IDS", + "URLS", "EmbeddedFiles", "AlternatePresentations", "Renditions"}) + } + + for treeName, value := range d { + + if ok := validateNameTreeName(treeName); !ok { + return errors.Errorf("validateNames: unknown name tree name: %s\n", treeName) + } + + d, err := xRefTable.DereferenceDict(value) + if err != nil { + return err + } + if d == nil { + continue + } + + _, _, tree, err := validateNameTree(xRefTable, treeName, d, true) + if err != nil { + return err + } + + // Internalize this name tree. + // If no validation takes place, name trees have to be internalized via xRefTable.LocateNameTree + // TODO Move this out of validation into Read. + if tree != nil { + xRefTable.Names[treeName] = tree + } + + } + + return nil +} + +func validateNamedDestinations(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 12.3.2.3 Named Destinations + + // indRef or dict with destination array values. + + d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Dests", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + for _, o := range d { + err = validateDestination(xRefTable, o) + if err != nil { + return err + } + } + + return nil +} + +func validateViewerPreferences(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 12.2 Viewer Preferences + + dictName := "rootDict" + + d, err := validateDictEntry(xRefTable, rootDict, dictName, "ViewerPreferences", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + dictName = "ViewerPreferences" + + _, err = validateBooleanEntry(xRefTable, d, dictName, "HideToolbar", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateBooleanEntry(xRefTable, d, dictName, "HideMenubar", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateBooleanEntry(xRefTable, d, dictName, "HideWindowUI", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateBooleanEntry(xRefTable, d, dictName, "FitWindow", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + _, err = validateBooleanEntry(xRefTable, d, dictName, "CenterWindow", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + sinceVersion = pdf.V14 + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V10 + } + _, err = validateBooleanEntry(xRefTable, d, dictName, "DisplayDocTitle", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + validate := func(s string) bool { return pdf.MemberOf(s, []string{"UseNone", "UseOutlines", "UseThumbs", "UseOC"}) } + _, err = validateNameEntry(xRefTable, d, dictName, "NonFullScreenPageMode", OPTIONAL, pdf.V10, validate) + if err != nil { + return err + } + + validate = func(s string) bool { return pdf.MemberOf(s, []string{"L2R", "R2L"}) } + _, err = validateNameEntry(xRefTable, d, dictName, "Direction", OPTIONAL, pdf.V13, validate) + if err != nil { + return err + } + + _, err = validateNameEntry(xRefTable, d, dictName, "ViewArea", OPTIONAL, pdf.V14, nil) + + return err +} + +func validatePageLayout(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validateNameEntry(xRefTable, rootDict, "rootDict", "PageLayout", required, sinceVersion, nil) + + return err +} + +func validatePageMode(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validateNameEntry(xRefTable, rootDict, "rootDict", "PageMode", required, sinceVersion, nil) + + return err +} + +func validateOpenAction(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 12.3.2 Destinations, 12.6 Actions + + // A value specifying a destination that shall be displayed + // or an action that shall be performed when the document is opened. + // The value shall be either an array defining a destination (see 12.3.2, "Destinations") + // or an action dictionary representing an action (12.6, "Actions"). + // + // If this entry is absent, the document shall be opened + // to the top of the first page at the default magnification factor. + + o, err := validateEntry(xRefTable, rootDict, "rootDict", "OpenAction", required, sinceVersion) + if err != nil || o == nil { + return err + } + + switch o := o.(type) { + + case pdf.Dict: + err = validateActionDict(xRefTable, o) + + case pdf.Array: + err = validateDestinationArray(xRefTable, o) + + default: + err = errors.New("pdfcpu: validateOpenAction: unexpected object") + } + + return err +} + +func validateURI(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 12.6.4.7 URI Actions + + // URI dict with one optional entry Base, ASCII string + + d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "URI", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + // Base, optional, ASCII string + _, err = validateStringEntry(xRefTable, d, "URIdict", "Base", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateRootMetadata(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + return validateMetadata(xRefTable, rootDict, required, sinceVersion) +} + +func validateMetadata(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 14.3 Metadata + // In general, any PDF stream or dictionary may have metadata attached to it + // as long as the stream or dictionary represents an actual information resource, + // as opposed to serving as an implementation artifact. + // Some PDF constructs are considered implementational, and hence may not have associated metadata. + + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + + sd, err := validateStreamDictEntry(xRefTable, d, "dict", "Metadata", required, sinceVersion, nil) + if err != nil || sd == nil { + return err + } + + dictName := "metaDataDict" + + _, err = validateNameEntry(xRefTable, sd.Dict, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Metadata" }) + if err != nil { + return err + } + + _, err = validateNameEntry(xRefTable, sd.Dict, dictName, "Subtype", OPTIONAL, sinceVersion, func(s string) bool { return s == "XML" }) + + return err +} + +func validateMarkInfo(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 14.7 Logical Structure + + d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "MarkInfo", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + var isTaggedPDF bool + + dictName := "markInfoDict" + + // Marked, optional, boolean + marked, err := validateBooleanEntry(xRefTable, d, dictName, "Marked", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + if marked != nil { + isTaggedPDF = marked.Value() + } + + // Suspects: optional, since V1.6, boolean + suspects, err := validateBooleanEntry(xRefTable, d, dictName, "Suspects", OPTIONAL, pdf.V16, nil) + if err != nil { + return err + } + + if suspects != nil && suspects.Value() { + isTaggedPDF = false + } + + xRefTable.Tagged = isTaggedPDF + + // UserProperties: optional, since V1.6, boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "UserProperties", OPTIONAL, pdf.V16, nil) + + return err +} + +func validateLang(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validateStringEntry(xRefTable, rootDict, "rootDict", "Lang", required, sinceVersion, nil) + + return err +} + +func validateCaptureCommandDictArray(xRefTable *pdf.XRefTable, a pdf.Array) error { + + for _, o := range a { + + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateCaptureCommandDict(xRefTable, d) + if err != nil { + return err + } + + } + + return nil +} + +func validateWebCaptureInfoDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "webCaptureInfoDict" + + // V, required, since V1.3, number + _, err := validateNumberEntry(xRefTable, d, dictName, "V", REQUIRED, pdf.V13, nil) + if err != nil { + return err + } + + // C, optional, since V1.3, array of web capture command dict indRefs + a, err := validateIndRefArrayEntry(xRefTable, d, dictName, "C", OPTIONAL, pdf.V13, nil) + if err != nil { + return err + } + + if a != nil { + err = validateCaptureCommandDictArray(xRefTable, a) + } + + return err +} + +func validateSpiderInfo(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // 14.10.2 Web Capture Information Dictionary + + d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "SpiderInfo", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + return validateWebCaptureInfoDict(xRefTable, d) +} + +func validateOutputIntentDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "outputIntentDict" + + // Type, optional, name + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "OutputIntent" }) + if err != nil { + return err + } + + // S: required, name + _, err = validateNameEntry(xRefTable, d, dictName, "S", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // OutputCondition, optional, text string + _, err = validateStringEntry(xRefTable, d, dictName, "OutputCondition", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // OutputConditionIdentifier, required, text string + _, err = validateStringEntry(xRefTable, d, dictName, "OutputConditionIdentifier", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // RegistryName, optional, text string + _, err = validateStringEntry(xRefTable, d, dictName, "RegistryName", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // Info, optional, text string + _, err = validateStringEntry(xRefTable, d, dictName, "Info", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // DestOutputProfile, optional, streamDict + _, err = validateStreamDictEntry(xRefTable, d, dictName, "DestOutputProfile", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateOutputIntents(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 14.11.5 Output Intents + + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + sinceVersion = pdf.V13 + } + + a, err := validateArrayEntry(xRefTable, rootDict, "rootDict", "OutputIntents", required, sinceVersion, nil) + if err != nil || a == nil { + return err + } + + for _, o := range a { + + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateOutputIntentDict(xRefTable, d) + if err != nil { + return err + } + } + + return nil +} + +func validatePieceDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "pieceDict" + + for _, o := range d { + + d1, err := xRefTable.DereferenceDict(o) + if err != nil { + return err + } + + if d1 == nil { + continue + } + + required := REQUIRED + if xRefTable.ValidationMode == pdf.ValidationRelaxed { + required = OPTIONAL + } + _, err = validateDateEntry(xRefTable, d1, dictName, "LastModified", required, pdf.V10) + if err != nil { + return err + } + + _, err = validateEntry(xRefTable, d1, dictName, "Private", OPTIONAL, pdf.V10) + if err != nil { + return err + } + + } + + return nil +} + +func validateRootPieceInfo(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validatePieceInfo(xRefTable, rootDict, "rootDict", "PieceInfo", required, sinceVersion) + + return err +} + +func validatePieceInfo(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName string, required bool, sinceVersion pdf.Version) (hasPieceInfo bool, err error) { + + // 14.5 Page-Piece Dictionaries + + pieceDict, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil) + if err != nil || pieceDict == nil { + return false, err + } + + err = validatePieceDict(xRefTable, pieceDict) + + return hasPieceInfo, err +} + +// TODO implement +func validatePermissions(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 12.8.4 Permissions + + d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Permissions", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + return errors.New("pdfcpu: validatePermissions: not supported") +} + +// TODO implement +func validateLegal(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 12.8.5 Legal Content Attestations + + d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Legal", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + return errors.New("pdfcpu: validateLegal: not supported") +} + +func validateRequirementDict(xRefTable *pdf.XRefTable, d pdf.Dict, sinceVersion pdf.Version) error { + + dictName := "requirementDict" + + // Type, optional, name, + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Requirement" }) + if err != nil { + return err + } + + // S, required, name + _, err = validateNameEntry(xRefTable, d, dictName, "S", REQUIRED, sinceVersion, func(s string) bool { return s == "EnableJavaScripts" }) + if err != nil { + return err + } + + // The RH entry (requirement handler dicts) shall not be used in PDF 1.7. + + return nil +} + +func validateRequirements(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 12.10 Document Requirements + + a, err := validateArrayEntry(xRefTable, rootDict, "rootDict", "Requirements", required, sinceVersion, nil) + if err != nil || a == nil { + return err + } + + for _, o := range a { + + d, err := xRefTable.DereferenceDict(o) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateRequirementDict(xRefTable, d, sinceVersion) + if err != nil { + return err + } + + } + + return nil +} + +func validateCollectionFieldDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "colFlddict" + + _, err := validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, pdf.V10, func(s string) bool { return s == "CollectionField" }) + if err != nil { + return err + } + + // Subtype, required name + validateCollectionFieldSubtype := func(s string) bool { + return pdf.MemberOf(s, []string{"S", "D", "N", "F", "Desc", "ModDate", "CreationDate", "Size"}) + } + _, err = validateNameEntry(xRefTable, d, dictName, "Subtype", REQUIRED, pdf.V10, validateCollectionFieldSubtype) + if err != nil { + return err + } + + // N, required text string + _, err = validateStringEntry(xRefTable, d, dictName, "N", REQUIRED, pdf.V10, nil) + if err != nil { + return err + } + + // O, optional integer + _, err = validateIntegerEntry(xRefTable, d, dictName, "O", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // V, optional boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "V", OPTIONAL, pdf.V10, nil) + if err != nil { + return err + } + + // E, optional boolean + _, err = validateBooleanEntry(xRefTable, d, dictName, "E", OPTIONAL, pdf.V10, nil) + + return err +} + +func validateCollectionSchemaDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + for k, v := range d { + + if k == "Type" { + + var n pdf.Name + n, err := xRefTable.DereferenceName(v, pdf.V10, nil) + if err != nil { + return err + } + + if n != "CollectionSchema" { + return errors.New("pdfcpu: validateCollectionSchemaDict: invalid entry \"Type\"") + } + + continue + } + + d, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + + if d == nil { + continue + } + + err = validateCollectionFieldDict(xRefTable, d) + if err != nil { + return err + } + + } + + return nil +} + +func validateCollectionSortDict(xRefTable *pdf.XRefTable, d pdf.Dict) error { + + dictName := "colSortDict" + + // S, required name or array of names. + err := validateNameOrArrayOfNameEntry(xRefTable, d, dictName, "S", REQUIRED, pdf.V10) + if err != nil { + return err + } + + // A, optional boolean or array of booleans. + err = validateBooleanOrArrayOfBooleanEntry(xRefTable, d, dictName, "A", OPTIONAL, pdf.V10) + + return err +} + +func validateInitialView(s string) bool { return s == "D" || s == "T" || s == "H" } + +func validateCollection(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + // => 12.3.5 Collections + + d, err := validateDictEntry(xRefTable, rootDict, "rootDict", "Collection", required, sinceVersion, nil) + if err != nil || d == nil { + return err + } + + dictName := "Collection" + + _, err = validateNameEntry(xRefTable, d, dictName, "Type", OPTIONAL, sinceVersion, func(s string) bool { return s == "Collection" }) + if err != nil { + return err + } + + // Schema, optional dict + d1, err := validateDictEntry(xRefTable, d, dictName, "Schema", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateCollectionSchemaDict(xRefTable, d1) + if err != nil { + return err + } + } + + // D, optional string + _, err = validateStringEntry(xRefTable, d, dictName, "D", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + + // View, optional name + _, err = validateNameEntry(xRefTable, d, dictName, "View", OPTIONAL, sinceVersion, validateInitialView) + if err != nil { + return err + } + + // Sort, optional dict + d1, err = validateDictEntry(xRefTable, d, dictName, "Sort", OPTIONAL, sinceVersion, nil) + if err != nil { + return err + } + if d1 != nil { + err = validateCollectionSortDict(xRefTable, d1) + if err != nil { + return err + } + } + + return nil +} + +func validateNeedsRendering(xRefTable *pdf.XRefTable, rootDict pdf.Dict, required bool, sinceVersion pdf.Version) error { + + _, err := validateBooleanEntry(xRefTable, rootDict, "rootDict", "NeedsRendering", required, sinceVersion, nil) + + return err +} + +func validateRootObject(xRefTable *pdf.XRefTable) error { + + log.Validate.Println("*** validateRootObject begin ***") + + // => 7.7.2 Document Catalog + + // Entry opt since type info + // ------------------------------------------------------------------------------------ + // Type n string "Catalog" + // Version y 1.4 name overrules header version if later + // Extensions y ISO 32000 dict => 7.12 Extensions Dictionary + // Pages n - (dict) => 7.7.3 Page Tree + // PageLabels y 1.3 number tree => 7.9.7 Number Trees, 12.4.2 Page Labels + // Names y 1.2 dict => 7.7.4 Name Dictionary + // Dests y only 1.1 (dict) => 12.3.2.3 Named Destinations + // ViewerPreferences y 1.2 dict => 12.2 Viewer Preferences + // PageLayout y - name /SinglePage, /OneColumn etc. + // PageMode y - name /UseNone, /FullScreen etc. + // Outlines y - (dict) => 12.3.3 Document Outline + // Threads y 1.1 (array) => 12.4.3 Articles + // OpenAction y 1.1 array or dict => 12.3.2 Destinations, 12.6 Actions + // AA y 1.4 dict => 12.6.3 Trigger Events + // URI y 1.1 dict => 12.6.4.7 URI Actions + // AcroForm y 1.2 dict => 12.7.2 Interactive Form Dictionary + // Metadata y 1.4 (stream) => 14.3.2 Metadata Streams + // StructTreeRoot y 1.3 dict => 14.7.2 Structure Hierarchy + // Markinfo y 1.4 dict => 14.7 Logical Structure + // Lang y 1.4 string + // SpiderInfo y 1.3 dict => 14.10.2 Web Capture Information Dictionary + // OutputIntents y 1.4 array => 14.11.5 Output Intents + // PieceInfo y 1.4 dict => 14.5 Page-Piece Dictionaries + // OCProperties y 1.5 dict => 8.11.4 Configuring Optional Content + // Perms y 1.5 dict => 12.8.4 Permissions + // Legal y 1.5 dict => 12.8.5 Legal Content Attestations + // Requirements y 1.7 array => 12.10 Document Requirements + // Collection y 1.7 dict => 12.3.5 Collections + // NeedsRendering y 1.7 boolean => XML Forms Architecture (XFA) Spec. + + d, err := xRefTable.Catalog() + if err != nil { + return err + } + + // Type + _, err = validateNameEntry(xRefTable, d, "rootDict", "Type", REQUIRED, pdf.V10, func(s string) bool { return s == "Catalog" }) + if err != nil { + return err + } + + // Pages + rootPageNodeDict, err := validatePages(xRefTable, d) + if err != nil { + return err + } + + for _, f := range []struct { + validate func(xRefTable *pdf.XRefTable, d pdf.Dict, required bool, sinceVersion pdf.Version) (err error) + required bool + sinceVersion pdf.Version + }{ + {validateRootVersion, OPTIONAL, pdf.V14}, + {validateExtensions, OPTIONAL, pdf.V10}, + {validatePageLabels, OPTIONAL, pdf.V13}, + {validateNames, OPTIONAL, pdf.V12}, + {validateNamedDestinations, OPTIONAL, pdf.V11}, + {validateViewerPreferences, OPTIONAL, pdf.V12}, + {validatePageLayout, OPTIONAL, pdf.V10}, + {validatePageMode, OPTIONAL, pdf.V10}, + {validateOutlines, OPTIONAL, pdf.V10}, + {validateThreads, OPTIONAL, pdf.V11}, + {validateOpenAction, OPTIONAL, pdf.V11}, + {validateRootAdditionalActions, OPTIONAL, pdf.V14}, + {validateURI, OPTIONAL, pdf.V11}, + {validateAcroForm, OPTIONAL, pdf.V12}, + {validateRootMetadata, OPTIONAL, pdf.V14}, + {validateStructTree, OPTIONAL, pdf.V13}, + {validateMarkInfo, OPTIONAL, pdf.V14}, + {validateLang, OPTIONAL, pdf.V10}, + {validateSpiderInfo, OPTIONAL, pdf.V13}, + {validateOutputIntents, OPTIONAL, pdf.V14}, + {validateRootPieceInfo, OPTIONAL, pdf.V14}, + {validateOCProperties, OPTIONAL, pdf.V15}, + {validatePermissions, OPTIONAL, pdf.V15}, + {validateLegal, OPTIONAL, pdf.V17}, + {validateRequirements, OPTIONAL, pdf.V17}, + {validateCollection, OPTIONAL, pdf.V17}, + {validateNeedsRendering, OPTIONAL, pdf.V17}, + } { + if !f.required && xRefTable.Version() < f.sinceVersion { + // Ignore optional fields if currentVersion < sinceVersion + // This is really a workaround for explicitly extending relaxed validation. + continue + } + err = f.validate(xRefTable, d, f.required, f.sinceVersion) + if err != nil { + return err + } + } + + // Validate remainder of annotations after AcroForm validation only. + err = validatePagesAnnotations(xRefTable, rootPageNodeDict) + + if err == nil { + log.Validate.Println("*** validateRootObject end ***") + } + + return err +} + +func validateAdditionalStreams(xRefTable *pdf.XRefTable) error { + + // Out of spec scope. + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/version.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/version.go new file mode 100644 index 0000000..7456138 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/version.go @@ -0,0 +1,71 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + + "github.com/pkg/errors" +) + +// VersionStr is the current pdfcpu version. +var VersionStr = "v0.3.8 dev" + +// Version is a type for the internal representation of PDF versions. +type Version int + +// Constants for all PDF versions up to v1.7 +const ( + V10 Version = iota + V11 + V12 + V13 + V14 + V15 + V16 + V17 +) + +// PDFVersion returns the PDFVersion for a version string. +func PDFVersion(versionStr string) (Version, error) { + + switch versionStr { + case "1.0": + return V10, nil + case "1.1": + return V11, nil + case "1.2": + return V12, nil + case "1.3": + return V13, nil + case "1.4": + return V14, nil + case "1.5": + return V15, nil + case "1.6": + return V16, nil + case "1.7": + return V17, nil + } + + return -1, errors.New(versionStr) +} + +// String returns a string representation for a given PDFVersion. +func (v Version) String() string { + return "1." + fmt.Sprintf("%d", v) +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/write.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/write.go new file mode 100644 index 0000000..cf5faa0 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/write.go @@ -0,0 +1,987 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "bufio" + "bytes" + "encoding/hex" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +// Write generates a PDF file for the cross reference table contained in Context. +func Write(ctx *Context) (err error) { + // Create a writer for dirname and filename if not already supplied. + if ctx.Write.Writer == nil { + + fileName := filepath.Join(ctx.Write.DirName, ctx.Write.FileName) + log.CLI.Printf("writing to %s\n", fileName) + + file, err := os.Create(fileName) + if err != nil { + return errors.Wrapf(err, "can't create %s\n%s", fileName, err) + } + + ctx.Write.Writer = bufio.NewWriter(file) + + defer func() { + + // The underlying bufio.Writer has already been flushed. + + // Processing error takes precedence. + if err != nil { + file.Close() + return + } + + // Do not miss out on closing errors. + err = file.Close() + + }() + + } + + if err = prepareContextForWriting(ctx); err != nil { + return err + } + + // Since we support PDF Collections (since V1.7) for file attachments + // we need to always generate V1.7 PDF files. + if err = writeHeader(ctx.Write, V17); err != nil { + return err + } + + // Ensure there is no root version. + if ctx.RootVersion != nil { + ctx.RootDict.Delete("Version") + } + + log.Write.Printf("offset after writeHeader: %d\n", ctx.Write.Offset) + + // Write root object(aka the document catalog) and page tree. + if err = writeRootObject(ctx); err != nil { + return err + } + + log.Write.Printf("offset after writeRootObject: %d\n", ctx.Write.Offset) + + // Write document information dictionary. + if err = ctx.writeDocumentInfoDict(); err != nil { + return err + } + + log.Write.Printf("offset after writeInfoObject: %d\n", ctx.Write.Offset) + + // Write offspec additional streams as declared in pdf trailer. + if err = writeAdditionalStreams(ctx); err != nil { + return err + } + + if err = writeEncryptDict(ctx); err != nil { + return err + } + + // Mark redundant objects as free. + // eg. duplicate resources, compressed objects, linearization dicts.. + deleteRedundantObjects(ctx) + + if err = writeXRef(ctx); err != nil { + return err + } + + // Write pdf trailer. + if _, err = writeTrailer(ctx.Write); err != nil { + return err + } + + if err = setFileSizeOfWrittenFile(ctx.Write); err != nil { + return err + } + + if ctx.Read != nil { + ctx.Write.BinaryImageSize = ctx.Read.BinaryImageSize + ctx.Write.BinaryFontSize = ctx.Read.BinaryFontSize + logWriteStats(ctx) + } + + return nil +} + +func prepareContextForWriting(ctx *Context) error { + + if err := ensureInfoDictAndFileID(ctx); err != nil { + return err + } + + return handleEncryption(ctx) +} + +func writeAdditionalStreams(ctx *Context) error { + + if ctx.AdditionalStreams == nil { + return nil + } + + if _, _, err := writeDeepObject(ctx, ctx.AdditionalStreams); err != nil { + return err + } + + return nil +} + +func ensureFileID(ctx *Context) error { + + fid, err := fileID(ctx) + if err != nil { + return err + } + + if ctx.ID == nil { + // Ensure ctx.ID + ctx.ID = Array{fid, fid} + return nil + } + + // Update ctx.ID + a := ctx.ID + if len(a) != 2 { + return errors.New("pdfcpu: ID must be an array with 2 elements") + } + + a[1] = fid + + return nil +} + +func ensureInfoDictAndFileID(ctx *Context) error { + + if err := ctx.ensureInfoDict(); err != nil { + return err + } + + return ensureFileID(ctx) +} + +// Write root entry to disk. +func writeRootEntry(ctx *Context, d Dict, dictName, entryName string, statsAttr int) error { + + o, err := writeEntry(ctx, d, dictName, entryName) + if err != nil { + return err + } + + if o != nil { + ctx.Stats.AddRootAttr(statsAttr) + } + + return nil +} + +// Write root entry to object stream. +func writeRootEntryToObjStream(ctx *Context, d Dict, dictName, entryName string, statsAttr int) error { + + ctx.Write.WriteToObjectStream = true + + if err := writeRootEntry(ctx, d, dictName, entryName, statsAttr); err != nil { + return err + } + + return stopObjectStream(ctx) +} + +// Write page tree. +func writePages(ctx *Context, rootDict Dict) error { + + // Page tree root (the top "Pages" dict) must be indirect reference. + ir := rootDict.IndirectRefEntry("Pages") + if ir == nil { + return errors.New("pdfcpu: writePages: missing indirect obj for pages dict") + } + + // Embed all page tree objects into objects stream. + ctx.Write.WriteToObjectStream = true + + // Write page tree. + p := 0 + if _, _, err := writePagesDict(ctx, ir, &p); err != nil { + return err + } + + return stopObjectStream(ctx) +} + +func writeRootObject(ctx *Context) error { + + // => 7.7.2 Document Catalog + + xRefTable := ctx.XRefTable + catalog := *xRefTable.Root + objNumber := int(catalog.ObjectNumber) + genNumber := int(catalog.GenerationNumber) + + log.Write.Printf("*** writeRootObject: begin offset=%d *** %s\n", ctx.Write.Offset, catalog) + + // Ensure corresponding and accurate name tree object graphs. + // if !ctx.ApplyReducedFeatureSet() { + if err := ctx.BindNameTrees(); err != nil { + return err + } + // } + + d, err := xRefTable.DereferenceDict(catalog) + if err != nil { + return err + } + + if d == nil { + return errors.Errorf("pdfcpu: writeRootObject: unable to dereference root dict") + } + + dictName := "rootDict" + + // if ctx.ApplyReducedFeatureSet() { + // log.Write.Println("writeRootObject - reducedFeatureSet:exclude complex entries.") + // d.Delete("Names") + // d.Delete("Dests") + // d.Delete("Outlines") + // d.Delete("OpenAction") + // d.Delete("AcroForm") + // d.Delete("StructTreeRoot") + // d.Delete("OCProperties") + // } + + if err = writeDictObject(ctx, objNumber, genNumber, d); err != nil { + return err + } + + log.Write.Printf("writeRootObject: %s\n", d) + + log.Write.Printf("writeRootObject: new offset after rootDict = %d\n", ctx.Write.Offset) + + if err = writeRootEntry(ctx, d, dictName, "Version", RootVersion); err != nil { + return err + } + + if err = writePages(ctx, d); err != nil { + return err + } + + for _, e := range []struct { + entryName string + statsAttr int + }{ + {"Extensions", RootExtensions}, + {"PageLabels", RootPageLabels}, + {"Names", RootNames}, + {"Dests", RootDests}, + {"ViewerPreferences", RootViewerPrefs}, + {"PageLayout", RootPageLayout}, + {"PageMode", RootPageMode}, + {"Outlines", RootOutlines}, + {"Threads", RootThreads}, + {"OpenAction", RootOpenAction}, + {"AA", RootAA}, + {"URI", RootURI}, + {"AcroForm", RootAcroForm}, + {"Metadata", RootMetadata}, + } { + if err = writeRootEntry(ctx, d, dictName, e.entryName, e.statsAttr); err != nil { + return err + } + } + + if err = writeRootEntryToObjStream(ctx, d, dictName, "StructTreeRoot", RootStructTreeRoot); err != nil { + return err + } + + for _, e := range []struct { + entryName string + statsAttr int + }{ + {"MarkInfo", RootMarkInfo}, + {"Lang", RootLang}, + {"SpiderInfo", RootSpiderInfo}, + {"OutputIntents", RootOutputIntents}, + {"PieceInfo", RootPieceInfo}, + {"OCProperties", RootOCProperties}, + {"Perms", RootPerms}, + {"Legal", RootLegal}, + {"Requirements", RootRequirements}, + {"Collection", RootCollection}, + {"NeedsRendering", RootNeedsRendering}, + } { + if err = writeRootEntry(ctx, d, dictName, e.entryName, e.statsAttr); err != nil { + return err + } + } + + log.Write.Printf("*** writeRootObject: end offset=%d ***\n", ctx.Write.Offset) + + return nil +} + +func writeTrailerDict(ctx *Context) error { + + log.Write.Printf("writeTrailerDict begin\n") + + w := ctx.Write + xRefTable := ctx.XRefTable + + if _, err := w.WriteString("trailer"); err != nil { + return err + } + + if err := w.WriteEol(); err != nil { + return err + } + + d := NewDict() + d.Insert("Size", Integer(*xRefTable.Size)) + d.Insert("Root", *xRefTable.Root) + + if xRefTable.Info != nil { + d.Insert("Info", *xRefTable.Info) + } + + if ctx.Encrypt != nil && ctx.EncKey != nil { + d.Insert("Encrypt", *ctx.Encrypt) + } + + if xRefTable.ID != nil { + d.Insert("ID", xRefTable.ID) + } + + if _, err := w.WriteString(d.PDFString()); err != nil { + return err + } + + log.Write.Printf("writeTrailerDict end\n") + + return nil +} + +func writeXRefSubsection(ctx *Context, start int, size int) error { + + log.Write.Printf("writeXRefSubsection: start=%d size=%d\n", start, size) + + w := ctx.Write + + if _, err := w.WriteString(fmt.Sprintf("%d %d%s", start, size, w.Eol)); err != nil { + return err + } + + var lines []string + + for i := start; i < start+size; i++ { + + entry := ctx.XRefTable.Table[i] + + if entry.Compressed { + return errors.New("pdfcpu: writeXRefSubsection: compressed entries present") + } + + var s string + + if entry.Free { + s = fmt.Sprintf("%010d %05d f%2s", *entry.Offset, *entry.Generation, w.Eol) + } else { + var off int64 + writeOffset, found := ctx.Write.Table[i] + if found { + off = writeOffset + } + s = fmt.Sprintf("%010d %05d n%2s", off, *entry.Generation, w.Eol) + } + + lines = append(lines, fmt.Sprintf("%d: %s", i, s)) + + if _, err := w.WriteString(s); err != nil { + return err + } + } + + log.Write.Printf("\n%s\n", strings.Join(lines, "")) + log.Write.Printf("writeXRefSubsection: end\n") + + return nil +} + +func deleteRedundantObject(ctx *Context, objNr int) { + + if len(ctx.Write.SelectedPages) == 0 && + (ctx.Optimize.IsDuplicateFontObject(objNr) || ctx.Optimize.IsDuplicateImageObject(objNr)) { + ctx.DeleteObject(objNr) + } + + if ctx.IsLinearizationObject(objNr) || ctx.Optimize.IsDuplicateInfoObject(objNr) || + ctx.Read.IsObjectStreamObject(objNr) || ctx.Read.IsXRefStreamObject(objNr) { + ctx.DeleteObject(objNr) + } + +} +func deleteRedundantObjects(ctx *Context) { + + if ctx.Optimize == nil { + return + } + + xRefTable := ctx.XRefTable + + log.Write.Printf("deleteRedundantObjects begin: Size=%d\n", *xRefTable.Size) + + for i := 0; i < *xRefTable.Size; i++ { + + // Missing object remains missing. + entry, found := xRefTable.Find(i) + if !found { + continue + } + + // Free object + if entry.Free { + continue + } + + // Object written + if ctx.Write.HasWriteOffset(i) { + // Resources may be cross referenced from different objects + // eg. font descriptors may be shared by different font dicts. + // Try to remove this object from the list of the potential duplicate objects. + log.Write.Printf("deleteRedundantObjects: remove duplicate obj #%d\n", i) + delete(ctx.Optimize.DuplicateFontObjs, i) + delete(ctx.Optimize.DuplicateImageObjs, i) + delete(ctx.Optimize.DuplicateInfoObjects, i) + continue + } + + // Object not written + + if ctx.Read.Linearized && entry.Offset != nil { + // This block applies to pre existing objects only. + // Since there is no type entry for stream dicts associated with linearization dicts + // we have to check every StreamDict that has not been written. + if _, ok := entry.Object.(StreamDict); ok { + + if *entry.Offset == *xRefTable.OffsetPrimaryHintTable { + xRefTable.LinearizationObjs[i] = true + log.Write.Printf("deleteRedundantObjects: primaryHintTable at obj #%d\n", i) + } + + if xRefTable.OffsetOverflowHintTable != nil && + *entry.Offset == *xRefTable.OffsetOverflowHintTable { + xRefTable.LinearizationObjs[i] = true + log.Write.Printf("deleteRedundantObjects: overflowHintTable at obj #%d\n", i) + } + + } + + } + + deleteRedundantObject(ctx, i) + + } + + log.Write.Println("deleteRedundantObjects end") +} + +func sortedWritableKeys(ctx *Context) []int { + + var keys []int + + for i, e := range ctx.Table { + if e.Free || ctx.Write.HasWriteOffset(i) { + keys = append(keys, i) + } + } + + sort.Ints(keys) + + return keys +} + +// After inserting the last object write the cross reference table to disk. +func writeXRefTable(ctx *Context) error { + + if err := ctx.EnsureValidFreeList(); err != nil { + return err + } + + keys := sortedWritableKeys(ctx) + + objCount := len(keys) + log.Write.Printf("xref has %d entries\n", objCount) + + if _, err := ctx.Write.WriteString("xref"); err != nil { + return err + } + + if err := ctx.Write.WriteEol(); err != nil { + return err + } + + start := keys[0] + size := 1 + + for i := 1; i < len(keys); i++ { + + if keys[i]-keys[i-1] > 1 { + + if err := writeXRefSubsection(ctx, start, size); err != nil { + return err + } + + start = keys[i] + size = 1 + continue + } + + size++ + } + + if err := writeXRefSubsection(ctx, start, size); err != nil { + return err + } + + if err := writeTrailerDict(ctx); err != nil { + return err + } + + if err := ctx.Write.WriteEol(); err != nil { + return err + } + + if _, err := ctx.Write.WriteString("startxref"); err != nil { + return err + } + + if err := ctx.Write.WriteEol(); err != nil { + return err + } + + if _, err := ctx.Write.WriteString(fmt.Sprintf("%d", ctx.Write.Offset)); err != nil { + return err + } + + return ctx.Write.WriteEol() +} + +// int64ToBuf returns a byte slice with length byteCount representing integer i. +func int64ToBuf(i int64, byteCount int) (buf []byte) { + + j := 0 + var b []byte + + for k := i; k > 0; { + b = append(b, byte(k&0xff)) + k >>= 8 + j++ + } + + // Swap byte order + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] + } + + if j < byteCount { + buf = append(bytes.Repeat([]byte{0}, byteCount-j), b...) + } else { + buf = b + } + + return +} + +func createXRefStream(ctx *Context, i1, i2, i3 int) ([]byte, *Array, error) { + + log.Write.Println("createXRefStream begin") + + xRefTable := ctx.XRefTable + + var ( + buf []byte + a Array + ) + + var keys []int + for i, e := range xRefTable.Table { + if e.Free || ctx.Write.HasWriteOffset(i) { + keys = append(keys, i) + } + } + sort.Ints(keys) + + objCount := len(keys) + log.Write.Printf("createXRefStream: xref has %d entries\n", objCount) + + start := keys[0] + size := 0 + + for i := 0; i < len(keys); i++ { + + j := keys[i] + entry := xRefTable.Table[j] + var s1, s2, s3 []byte + + if entry.Free { + + // unused + log.Write.Printf("createXRefStream: unused i=%d nextFreeAt:%d gen:%d\n", j, int(*entry.Offset), int(*entry.Generation)) + + s1 = int64ToBuf(0, i1) + s2 = int64ToBuf(*entry.Offset, i2) + s3 = int64ToBuf(int64(*entry.Generation), i3) + + } else if entry.Compressed { + + // in use, compressed into object stream + log.Write.Printf("createXRefStream: compressed i=%d at objstr %d[%d]\n", j, int(*entry.ObjectStream), int(*entry.ObjectStreamInd)) + + s1 = int64ToBuf(2, i1) + s2 = int64ToBuf(int64(*entry.ObjectStream), i2) + s3 = int64ToBuf(int64(*entry.ObjectStreamInd), i3) + + } else { + + off, found := ctx.Write.Table[j] + if !found { + return nil, nil, errors.Errorf("pdfcpu: createXRefStream: missing write offset for obj #%d\n", i) + } + + // in use, uncompressed + log.Write.Printf("createXRefStream: used i=%d offset:%d gen:%d\n", j, int(off), int(*entry.Generation)) + + s1 = int64ToBuf(1, i1) + s2 = int64ToBuf(off, i2) + s3 = int64ToBuf(int64(*entry.Generation), i3) + + } + + log.Write.Printf("createXRefStream: written: %x %x %x \n", s1, s2, s3) + + buf = append(buf, s1...) + buf = append(buf, s2...) + buf = append(buf, s3...) + + if i > 0 && (keys[i]-keys[i-1] > 1) { + + a = append(a, Integer(start)) + a = append(a, Integer(size)) + + start = keys[i] + size = 1 + continue + } + + size++ + } + + a = append(a, Integer(start)) + a = append(a, Integer(size)) + + log.Write.Println("createXRefStream end") + + return buf, &a, nil +} + +func writeXRefStream(ctx *Context) error { + + log.Write.Println("writeXRefStream begin") + + xRefTable := ctx.XRefTable + xRefStreamDict := NewXRefStreamDict(ctx) + xRefTableEntry := NewXRefTableEntryGen0(*xRefStreamDict) + + // Reuse free objects (including recycled objects from this run). + objNumber, err := xRefTable.InsertAndUseRecycled(*xRefTableEntry) + if err != nil { + return err + } + + // After the last insert of an object. + if err = xRefTable.EnsureValidFreeList(); err != nil { + return err + } + + xRefStreamDict.Insert("Size", Integer(*xRefTable.Size)) + + offset := ctx.Write.Offset + + i2Base := int64(*ctx.Size) + if offset > i2Base { + i2Base = offset + } + + i1 := 1 // 0, 1 or 2 always fit into 1 byte. + + i2 := func(i int64) (byteCount int) { + for i > 0 { + i >>= 8 + byteCount++ + } + return byteCount + }(i2Base) + + i3 := 2 // scale for max objectstream index <= 0x ff ff + + wArr := Array{Integer(i1), Integer(i2), Integer(i3)} + xRefStreamDict.Insert("W", wArr) + + // Generate xRefStreamDict data = xref entries -> xRefStreamDict.Content + content, indArr, err := createXRefStream(ctx, i1, i2, i3) + if err != nil { + return err + } + + xRefStreamDict.Content = content + xRefStreamDict.Insert("Index", *indArr) + + // Encode xRefStreamDict.Content -> xRefStreamDict.Raw + if err = xRefStreamDict.StreamDict.Encode(); err != nil { + return err + } + + log.Write.Printf("writeXRefStream: xRefStreamDict: %s\n", xRefStreamDict) + + if err = writeStreamDictObject(ctx, objNumber, 0, xRefStreamDict.StreamDict); err != nil { + return err + } + + w := ctx.Write + + if err = w.WriteEol(); err != nil { + return err + } + + if _, err = w.WriteString("startxref"); err != nil { + return err + } + + if err = w.WriteEol(); err != nil { + return err + } + + if _, err = w.WriteString(fmt.Sprintf("%d", offset)); err != nil { + return err + } + + if err = w.WriteEol(); err != nil { + return err + } + + log.Write.Println("writeXRefStream end") + + return nil +} + +func writeEncryptDict(ctx *Context) error { + + // Bail out unless we really have to write encrypted. + if ctx.Encrypt == nil || ctx.EncKey == nil { + return nil + } + + ir := *ctx.Encrypt + objNumber := int(ir.ObjectNumber) + genNumber := int(ir.GenerationNumber) + + d, err := ctx.DereferenceDict(ir) + if err != nil { + return err + } + + return writeObject(ctx, objNumber, genNumber, d.PDFString()) +} + +func setupEncryption(ctx *Context) error { + + var err error + + if ok := validateAlgorithm(ctx); !ok { + return errors.New("pdfcpu: unsupported encryption algorithm") + } + + d := newEncryptDict( + ctx.EncryptUsingAES, + ctx.EncryptKeyLength, + ctx.Permissions, + ) + + if ctx.E, err = supportedEncryption(ctx, d); err != nil { + return err + } + + if ctx.ID == nil { + return errors.New("pdfcpu: encrypt: missing ID") + } + + var id []byte + if id, err = ctx.IDFirstElement(); err != nil { + return err + } + + ctx.E.ID = id + + if err = calcOAndU(ctx, d); err != nil { + return err + } + + if err = writePermissions(ctx, d); err != nil { + return err + } + + xRefTableEntry := NewXRefTableEntryGen0(d) + + // Reuse free objects (including recycled objects from this run). + objNumber, err := ctx.InsertAndUseRecycled(*xRefTableEntry) + if err != nil { + return err + } + + ctx.Encrypt = NewIndirectRef(objNumber, 0) + + return nil +} + +func updateEncryption(ctx *Context) error { + + d, err := ctx.EncryptDict() + if err != nil { + return err + } + + if ctx.Cmd == SETPERMISSIONS { + //fmt.Printf("updating permissions to: %v\n", ctx.UserAccessPermissions) + ctx.E.P = int(ctx.Permissions) + d.Update("P", Integer(ctx.E.P)) + // and moving on, U is dependent on P + } + + // ctx.Cmd == CHANGEUPW or CHANGE OPW + + if ctx.UserPWNew != nil { + //fmt.Printf("change upw from <%s> to <%s>\n", ctx.UserPW, *ctx.UserPWNew) + ctx.UserPW = *ctx.UserPWNew + } + + if ctx.OwnerPWNew != nil { + //fmt.Printf("change opw from <%s> to <%s>\n", ctx.OwnerPW, *ctx.OwnerPWNew) + ctx.OwnerPW = *ctx.OwnerPWNew + } + + if ctx.E.R == 5 { + + if err = calcOAndU(ctx, d); err != nil { + return err + } + + return writePermissions(ctx, d) + } + + //fmt.Printf("opw before: length:%d <%s>\n", len(ctx.E.O), ctx.E.O) + if ctx.E.O, err = o(ctx); err != nil { + return err + } + //fmt.Printf("opw after: length:%d <%s> %0X\n", len(ctx.E.O), ctx.E.O, ctx.E.O) + d.Update("O", HexLiteral(hex.EncodeToString(ctx.E.O))) + + //fmt.Printf("upw before: length:%d <%s>\n", len(ctx.E.U), ctx.E.U) + if ctx.E.U, ctx.EncKey, err = u(ctx); err != nil { + return err + } + //fmt.Printf("upw after: length:%d <%s> %0X\n", len(ctx.E.U), ctx.E.U, ctx.E.U) + //fmt.Printf("encKey = %0X\n", ctx.EncKey) + d.Update("U", HexLiteral(hex.EncodeToString(ctx.E.U))) + + return nil +} + +func handleEncryption(ctx *Context) error { + + if ctx.Cmd == ENCRYPT || ctx.Cmd == DECRYPT { + + if ctx.Cmd == DECRYPT { + + // Remove encryption. + ctx.EncKey = nil + + } else { + + if err := setupEncryption(ctx); err != nil { + return err + } + + alg := "RC4" + if ctx.EncryptUsingAES { + alg = "AES" + } + log.CLI.Printf("using %s-%d\n", alg, ctx.EncryptKeyLength) + } + + } else if ctx.UserPWNew != nil || ctx.OwnerPWNew != nil || ctx.Cmd == SETPERMISSIONS { + + if err := updateEncryption(ctx); err != nil { + return err + } + + } + + // write xrefstream if using xrefstream only. + if ctx.Encrypt != nil && ctx.EncKey != nil && !ctx.Read.UsingXRefStreams { + ctx.WriteObjectStream = false + ctx.WriteXRefStream = false + } + + return nil +} + +func writeXRef(ctx *Context) error { + + if ctx.WriteXRefStream { + // Write cross reference stream and generate objectstreams. + return writeXRefStream(ctx) + } + + // Write cross reference table section. + return writeXRefTable(ctx) +} + +func setFileSizeOfWrittenFile(w *WriteContext) error { + if err := w.Flush(); err != nil { + return err + } + + // If writing is Writer based then f is nil. + if w.Fp == nil { + return nil + } + + fileInfo, err := w.Fp.Stat() + if err != nil { + return err + } + + w.FileSize = fileInfo.Size() + + return nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/writeObjects.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/writeObjects.go new file mode 100644 index 0000000..41a41a3 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/writeObjects.go @@ -0,0 +1,734 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +const ( + + // ObjectStreamMaxObjects limits the number of objects within an object stream written. + ObjectStreamMaxObjects = 100 +) + +func writeCommentLine(w *WriteContext, comment string) (int, error) { + return w.WriteString(fmt.Sprintf("%%%s%s", comment, w.Eol)) +} + +func writeHeader(w *WriteContext, v Version) error { + + i, err := writeCommentLine(w, "PDF-"+v.String()) + if err != nil { + return err + } + + j, err := writeCommentLine(w, "\xe2\xe3\xcf\xD3") + if err != nil { + return err + } + + w.Offset += int64(i + j) + + return nil +} + +func writeTrailer(w *WriteContext) (int, error) { + return w.WriteString("%%EOF") +} + +func writeObjectHeader(w *WriteContext, objNumber, genNumber int) (int, error) { + return w.WriteString(fmt.Sprintf("%d %d obj%s", objNumber, genNumber, w.Eol)) +} + +func writeObjectTrailer(w *WriteContext) (int, error) { + return w.WriteString(fmt.Sprintf("%sendobj%s", w.Eol, w.Eol)) +} + +func startObjectStream(ctx *Context) error { + + // See 7.5.7 Object streams + // When new object streams and compressed objects are created, they shall always be assigned new object numbers. + + log.Write.Println("startObjectStream begin") + + objStreamDict := NewObjectStreamDict() + + objNr, err := ctx.InsertObject(*objStreamDict) + if err != nil { + return err + } + + ctx.Write.CurrentObjStream = &objNr + + log.Write.Printf("startObjectStream end: %d\n", objNr) + + return nil +} + +func stopObjectStream(ctx *Context) error { + + log.Write.Println("stopObjectStream begin") + + xRefTable := ctx.XRefTable + + if !ctx.Write.WriteToObjectStream { + return errors.Errorf("stopObjectStream: Not writing to object stream.") + } + + if ctx.Write.CurrentObjStream == nil { + ctx.Write.WriteToObjectStream = false + log.Write.Println("stopObjectStream end (no content)") + return nil + } + + entry, _ := xRefTable.FindTableEntry(*ctx.Write.CurrentObjStream, 0) + osd, _ := (entry.Object).(ObjectStreamDict) + + // When we are ready to write: append prolog and content + osd.Finalize() + + // Encode objStreamDict.Content -> objStreamDict.Raw + // and wipe (decoded) content to free up memory. + if err := osd.StreamDict.Encode(); err != nil { + return err + } + + // Release memory. + osd.Content = nil + + osd.StreamDict.Insert("First", Integer(osd.FirstObjOffset)) + osd.StreamDict.Insert("N", Integer(osd.ObjCount)) + + // for each objStream execute at the end right before xRefStreamDict gets written. + log.Write.Printf("stopObjectStream: objStreamDict: %s\n", osd) + + if err := writeStreamDictObject(ctx, *ctx.Write.CurrentObjStream, 0, osd.StreamDict); err != nil { + return err + } + + // Release memory. + osd.Raw = nil + + ctx.Write.CurrentObjStream = nil + ctx.Write.WriteToObjectStream = false + + log.Write.Println("stopObjectStream end") + + return nil +} + +func writeToObjectStream(ctx *Context, objNumber, genNumber int) (ok bool, err error) { + + log.Write.Printf("addToObjectStream begin, obj#:%d gen#:%d\n", objNumber, genNumber) + + w := ctx.Write + + if ctx.WriteXRefStream && // object streams assume an xRefStream to be generated. + ctx.WriteObjectStream && // signal for compression into object stream is on. + ctx.Write.WriteToObjectStream && // currently writing to object stream. + genNumber == 0 { + + if w.CurrentObjStream == nil { + // Create new objects stream on first write. + err = startObjectStream(ctx) + if err != nil { + return false, err + } + } + + objStrEntry, _ := ctx.FindTableEntry(*ctx.Write.CurrentObjStream, 0) + objStreamDict, _ := (objStrEntry.Object).(ObjectStreamDict) + + // Get next free index in object stream. + i := objStreamDict.ObjCount + + // Locate the xref table entry for the object to be added to this object stream. + entry, _ := ctx.FindTableEntry(objNumber, genNumber) + + // Turn entry into a compressed entry located in object stream at index i. + entry.Compressed = true + entry.ObjectStream = ctx.Write.CurrentObjStream // ! + entry.ObjectStreamInd = &i + w.SetWriteOffset(objNumber) // for a compressed obj this is supposed to be a fake offset. value does not matter. + + // Append to prolog & content + err = objStreamDict.AddObject(objNumber, entry) + if err != nil { + return false, err + } + + objStrEntry.Object = objStreamDict + + log.Write.Printf("writeObject end, obj#%d written to objectStream #%d\n", objNumber, *ctx.Write.CurrentObjStream) + + if objStreamDict.ObjCount == ObjectStreamMaxObjects { + err = stopObjectStream(ctx) + if err != nil { + return false, err + } + w.WriteToObjectStream = true + } + + ok = true + + } + + log.Write.Printf("addToObjectStream end, obj#:%d gen#:%d\n", objNumber, genNumber) + + return ok, nil +} + +func writeObject(ctx *Context, objNumber, genNumber int, s string) error { + + log.Write.Printf("writeObject begin, obj#:%d gen#:%d <%s>\n", objNumber, genNumber, s) + + w := ctx.Write + + // Cleanup entry (necessary for split command) + // TODO This is not the right place to check for an existing obj since we maybe writing NULL. + entry, ok := ctx.FindTableEntry(objNumber, genNumber) + if ok { + entry.Compressed = false + } + + // Set write-offset for this object. + w.SetWriteOffset(objNumber) + + written, err := writeObjectHeader(w, objNumber, genNumber) + if err != nil { + return err + } + + // Note: Lines that are not part of stream object data are limited to no more than 255 characters. + i, err := w.WriteString(s) + if err != nil { + return err + } + + j, err := writeObjectTrailer(w) + if err != nil { + return err + } + + // Write-offset for next object. + w.Offset += int64(written + i + j) + + log.Write.Printf("writeObject end, %d bytes written\n", written+i+j) + + return nil +} + +func writePDFNullObject(ctx *Context, objNumber, genNumber int) error { + + return writeObject(ctx, objNumber, genNumber, "null") +} + +func writeBooleanObject(ctx *Context, objNumber, genNumber int, boolean Boolean) error { + + ok, err := writeToObjectStream(ctx, objNumber, genNumber) + if err != nil { + return err + } + + if ok { + return nil + } + + return writeObject(ctx, objNumber, genNumber, boolean.PDFString()) +} + +func writeNameObject(ctx *Context, objNumber, genNumber int, name Name) error { + + ok, err := writeToObjectStream(ctx, objNumber, genNumber) + if err != nil { + return err + } + + if ok { + return nil + } + + return writeObject(ctx, objNumber, genNumber, name.PDFString()) +} + +func writeStringLiteralObject(ctx *Context, objNumber, genNumber int, stringLiteral StringLiteral) error { + + ok, err := writeToObjectStream(ctx, objNumber, genNumber) + if err != nil { + return err + } + + if ok { + return nil + } + + sl := stringLiteral + + if ctx.EncKey != nil { + s1, err := encryptString(stringLiteral.Value(), objNumber, genNumber, ctx.EncKey, ctx.AES4Strings, ctx.E.R) + if err != nil { + return err + } + + sl = StringLiteral(*s1) + } + + return writeObject(ctx, objNumber, genNumber, sl.PDFString()) +} + +func writeHexLiteralObject(ctx *Context, objNumber, genNumber int, hexLiteral HexLiteral) error { + + ok, err := writeToObjectStream(ctx, objNumber, genNumber) + if err != nil { + return err + } + + if ok { + return nil + } + + hl := hexLiteral + + if ctx.EncKey != nil { + s1, err := encryptString(hexLiteral.Value(), objNumber, genNumber, ctx.EncKey, ctx.AES4Strings, ctx.E.R) + if err != nil { + return err + } + + hl = HexLiteral(*s1) + } + + return writeObject(ctx, objNumber, genNumber, hl.PDFString()) +} + +func writeIntegerObject(ctx *Context, objNumber, genNumber int, integer Integer) error { + + ok, err := writeToObjectStream(ctx, objNumber, genNumber) + if err != nil { + return err + } + + if ok { + return nil + } + + return writeObject(ctx, objNumber, genNumber, integer.PDFString()) +} + +func writeFloatObject(ctx *Context, objNumber, genNumber int, float Float) error { + + ok, err := writeToObjectStream(ctx, objNumber, genNumber) + if err != nil { + return err + } + + if ok { + return nil + } + + return writeObject(ctx, objNumber, genNumber, float.PDFString()) +} + +func writeDictObject(ctx *Context, objNumber, genNumber int, d Dict) error { + + ok, err := writeToObjectStream(ctx, objNumber, genNumber) + if err != nil { + return err + } + + if ok { + return nil + } + + if ctx.EncKey != nil { + _, err := encryptDeepObject(d, objNumber, genNumber, ctx.EncKey, ctx.AES4Strings, ctx.E.R) + if err != nil { + return err + } + } + + return writeObject(ctx, objNumber, genNumber, d.PDFString()) +} + +func writeArrayObject(ctx *Context, objNumber, genNumber int, a Array) error { + + ok, err := writeToObjectStream(ctx, objNumber, genNumber) + if err != nil { + return err + } + + if ok { + return nil + } + + if ctx.EncKey != nil { + _, err := encryptDeepObject(a, objNumber, genNumber, ctx.EncKey, ctx.AES4Strings, ctx.E.R) + if err != nil { + return err + } + } + + return writeObject(ctx, objNumber, genNumber, a.PDFString()) +} + +func writeStream(w *WriteContext, sd StreamDict) (int64, error) { + + b, err := w.WriteString(fmt.Sprintf("%sstream%s", w.Eol, w.Eol)) + if err != nil { + return 0, errors.Wrapf(err, "writeStream: failed to write raw content") + } + + c, err := w.Write(sd.Raw) + if err != nil { + return 0, errors.Wrapf(err, "writeStream: failed to write raw content") + } + if int64(c) != *sd.StreamLength { + return 0, errors.Errorf("writeStream: failed to write raw content: %d bytes written - streamlength:%d", c, *sd.StreamLength) + } + + e, err := w.WriteString("endstream") + if err != nil { + return 0, errors.Wrapf(err, "writeStream: failed to write raw content") + } + + written := int64(b+e) + *sd.StreamLength + + return written, nil +} + +func handleIndirectLength(ctx *Context, ir *IndirectRef) error { + + objNr := int(ir.ObjectNumber) + genNr := int(ir.GenerationNumber) + + if ctx.Write.HasWriteOffset(objNr) { + log.Write.Printf("*** handleIndirectLength: object #%d already written offset=%d ***\n", objNr, ctx.Write.Offset) + } else { + length, err := ctx.DereferenceInteger(*ir) + if err != nil || length == nil { + return err + } + err = writeIntegerObject(ctx, objNr, genNr, *length) + if err != nil { + return err + } + } + + return nil +} + +func writeStreamDictObject(ctx *Context, objNumber, genNumber int, sd StreamDict) error { + + log.Write.Printf("writeStreamDictObject begin: object #%d\n%v", objNumber, sd) + + var inObjStream bool + + if ctx.Write.WriteToObjectStream == true { + inObjStream = true + ctx.Write.WriteToObjectStream = false + } + + // Sometimes a streamDicts length is a reference. + if ir := sd.IndirectRefEntry("Length"); ir != nil { + err := handleIndirectLength(ctx, ir) + if err != nil { + return err + } + } + + var err error + + // Unless the "Identity" crypt filter is used we have to encrypt. + isXRefStreamDict := sd.Type() != nil && *sd.Type() == "XRef" + if ctx.EncKey != nil && + !isXRefStreamDict && + !(len(sd.FilterPipeline) == 1 && sd.FilterPipeline[0].Name == "Crypt") { + + sd.Raw, err = encryptStream(sd.Raw, objNumber, genNumber, ctx.EncKey, ctx.AES4Streams, ctx.E.R) + if err != nil { + return err + } + + l := int64(len(sd.Raw)) + sd.StreamLength = &l + sd.Update("Length", Integer(l)) + } + + ctx.Write.SetWriteOffset(objNumber) + + h, err := writeObjectHeader(ctx.Write, objNumber, genNumber) + if err != nil { + return err + } + + // Note: Lines that are not part of stream object data are limited to no more than 255 characters. + pdfString := sd.PDFString() + _, err = ctx.Write.WriteString(pdfString) + if err != nil { + return err + } + + b, err := writeStream(ctx.Write, sd) + if err != nil { + return err + } + + t, err := writeObjectTrailer(ctx.Write) + if err != nil { + return err + } + + written := b + int64(h+len(pdfString)+t) + + ctx.Write.Offset += written + ctx.Write.BinaryTotalSize += *sd.StreamLength + + if inObjStream { + ctx.Write.WriteToObjectStream = true + } + + log.Write.Printf("writeStreamDictObject end: object #%d written=%d\n", objNumber, written) + + return nil +} + +func writeDirectObject(ctx *Context, o Object) error { + + switch o := o.(type) { + + case Dict: + for k, v := range o { + if ctx.writingPages && (k == "Dest" || k == "D") { + ctx.dest = true + } + _, _, err := writeDeepObject(ctx, v) + if err != nil { + return err + } + ctx.dest = false + } + log.Write.Printf("writeDirectObject: end offset=%d\n", ctx.Write.Offset) + + case Array: + for i, v := range o { + if ctx.dest && i == 0 { + continue + } + _, _, err := writeDeepObject(ctx, v) + if err != nil { + return err + } + } + log.Write.Printf("writeDirectObject: end offset=%d\n", ctx.Write.Offset) + + default: + log.Write.Printf("writeDirectObject: end, direct obj - nothing written: offset=%d\n%v\n", ctx.Write.Offset, o) + + } + + return nil +} + +func writeNullObject(ctx *Context, objNumber, genNumber int) error { + + // An indirect reference to nil is a corner case. + // Still, it is an object that will be written. + err := writePDFNullObject(ctx, objNumber, genNumber) + if err != nil { + return err + } + + // Ensure no entry in free list. + return ctx.UndeleteObject(objNumber) +} + +func writeDeepDict(ctx *Context, d Dict, objNr, genNr int) error { + + err := writeDictObject(ctx, objNr, genNr, d) + if err != nil { + return err + } + + for k, v := range d { + if ctx.writingPages && (k == "Dest" || k == "D") { + ctx.dest = true + } + _, _, err = writeDeepObject(ctx, v) + if err != nil { + return err + } + ctx.dest = false + } + + return nil +} + +func writeDeepStreamDict(ctx *Context, sd *StreamDict, objNr, genNr int) error { + + if ctx.EncKey != nil { + _, err := encryptDeepObject(*sd, objNr, genNr, ctx.EncKey, ctx.AES4Strings, ctx.E.R) + if err != nil { + return err + } + } + + err := writeStreamDictObject(ctx, objNr, genNr, *sd) + if err != nil { + return err + } + + for _, v := range sd.Dict { + _, _, err = writeDeepObject(ctx, v) + if err != nil { + return err + } + } + + return nil +} + +func writeDeepArray(ctx *Context, a Array, objNr, genNr int) error { + + err := writeArrayObject(ctx, objNr, genNr, a) + if err != nil { + return err + } + + for i, v := range a { + if ctx.dest && i == 0 { + continue + } + _, _, err = writeDeepObject(ctx, v) + if err != nil { + return err + } + } + + return nil +} + +func writeIndirectObject(ctx *Context, ir IndirectRef) (Object, error) { + + objNr := int(ir.ObjectNumber) + genNr := int(ir.GenerationNumber) + + if ctx.Write.HasWriteOffset(objNr) { + log.Write.Printf("writeIndirectObject end: object #%d already written.\n", objNr) + return nil, nil + } + + o, err := ctx.Dereference(ir) + if err != nil { + return nil, errors.Wrapf(err, "writeIndirectObject: unable to dereference indirect object #%d", objNr) + } + + log.Write.Printf("writeIndirectObject: object #%d gets writeoffset: %d\n", objNr, ctx.Write.Offset) + + if o == nil { + + err = writeNullObject(ctx, objNr, genNr) + if err != nil { + return nil, err + } + + log.Write.Printf("writeIndirectObject: end, obj#%d resolved to nil, offset=%d\n", objNr, ctx.Write.Offset) + return nil, nil + } + + switch o := o.(type) { + + case Dict: + err = writeDeepDict(ctx, o, objNr, genNr) + + case StreamDict: + err = writeDeepStreamDict(ctx, &o, objNr, genNr) + + case Array: + err = writeDeepArray(ctx, o, objNr, genNr) + + case Integer: + err = writeIntegerObject(ctx, objNr, genNr, o) + + case Float: + err = writeFloatObject(ctx, objNr, genNr, o) + + case StringLiteral: + err = writeStringLiteralObject(ctx, objNr, genNr, o) + + case HexLiteral: + err = writeHexLiteralObject(ctx, objNr, genNr, o) + + case Boolean: + err = writeBooleanObject(ctx, objNr, genNr, o) + + case Name: + err = writeNameObject(ctx, objNr, genNr, o) + + default: + return nil, errors.Errorf("writeIndirectObject: undefined PDF object #%d %T\n", objNr, o) + + } + + return nil, err +} + +func writeDeepObject(ctx *Context, objIn Object) (objOut Object, written bool, err error) { + + log.Write.Printf("writeDeepObject: begin offset=%d\n%s\n", ctx.Write.Offset, objIn) + + ir, ok := objIn.(IndirectRef) + if !ok { + return objIn, written, writeDirectObject(ctx, objIn) + } + + objOut, err = writeIndirectObject(ctx, ir) + if err == nil { + written = true + log.Write.Printf("writeDeepObject: end offset=%d\n", ctx.Write.Offset) + } + + return objOut, written, err +} + +func writeEntry(ctx *Context, d Dict, dictName, entryName string) (Object, error) { + + o, found := d.Find(entryName) + if !found || o == nil { + log.Write.Printf("writeEntry end: entry %s is nil\n", entryName) + return nil, nil + } + + log.Write.Printf("writeEntry begin: dict=%s entry=%s offset=%d\n", dictName, entryName, ctx.Write.Offset) + + o, _, err := writeDeepObject(ctx, o) + if err != nil { + return nil, err + } + + if o == nil { + log.Write.Printf("writeEntry end: dict=%s entry=%s resolved to nil, offset=%d\n", dictName, entryName, ctx.Write.Offset) + return nil, nil + } + + log.Write.Printf("writeEntry end: dict=%s entry=%s offset=%d\n", dictName, entryName, ctx.Write.Offset) + + return o, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/writePages.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/writePages.go new file mode 100644 index 0000000..c3e47ce --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/writePages.go @@ -0,0 +1,283 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +// Write page entry to disk. +func writePageEntry(ctx *Context, d Dict, dictName, entryName string, statsAttr int) error { + + o, err := writeEntry(ctx, d, dictName, entryName) + if err != nil { + return err + } + + if o != nil { + ctx.Stats.AddPageAttr(statsAttr) + } + + return nil +} + +func writePageDict(ctx *Context, ir *IndirectRef, pageDict Dict, pageNr int) error { + + objNr := ir.ObjectNumber.Value() + genNr := ir.GenerationNumber.Value() + + if ctx.Write.HasWriteOffset(objNr) { + log.Write.Printf("writePageDict: object #%d already written.\n", objNr) + return nil + } + + log.Write.Printf("writePageDict: logical pageNr=%d object #%d gets writeoffset: %d\n", pageNr, objNr, ctx.Write.Offset) + + dictName := "pageDict" + + if err := writeDictObject(ctx, objNr, genNr, pageDict); err != nil { + return err + } + + log.Write.Printf("writePageDict: new offset = %d\n", ctx.Write.Offset) + + if ir := pageDict.IndirectRefEntry("Parent"); ir == nil { + return errors.New("pdfcpu: writePageDict: missing parent") + } + + ctx.writingPages = true + + for _, e := range []struct { + entryName string + statsAttr int + }{ + {"Contents", PageContents}, + {"Resources", PageResources}, + {"MediaBox", PageMediaBox}, + {"CropBox", PageCropBox}, + {"BleedBox", PageBleedBox}, + {"TrimBox", PageTrimBox}, + {"ArtBox", PageArtBox}, + {"BoxColorInfo", PageBoxColorInfo}, + {"PieceInfo", PagePieceInfo}, + {"LastModified", PageLastModified}, + {"Rotate", PageRotate}, + {"Group", PageGroup}, + {"Annots", PageAnnots}, + {"Thumb", PageThumb}, + {"B", PageB}, + {"Dur", PageDur}, + {"Trans", PageTrans}, + {"AA", PageAA}, + {"Metadata", PageMetadata}, + {"StructParents", PageStructParents}, + {"ID", PageID}, + {"PZ", PagePZ}, + {"SeparationInfo", PageSeparationInfo}, + {"Tabs", PageTabs}, + {"TemplateInstantiated", PageTemplateInstantiated}, + {"PresSteps", PagePresSteps}, + {"UserUnit", PageUserUnit}, + {"VP", PageVP}, + } { + if err := writePageEntry(ctx, pageDict, dictName, e.entryName, e.statsAttr); err != nil { + return err + } + } + + ctx.writingPages = false + + log.Write.Printf("*** writePageDict end: obj#%d offset=%d ***\n", objNr, ctx.Write.Offset) + + return nil +} + +func pageNodeDict(ctx *Context, o Object) (d Dict, indRef *IndirectRef, err error) { + + if o == nil { + log.Write.Println("pageNodeDict: is nil") + return nil, nil, nil + } + + // Dereference next page node dict. + ir, ok := o.(IndirectRef) + if !ok { + return nil, nil, errors.New("pdfcpu: pageNodeDict: missing indirect reference") + } + log.Write.Printf("pageNodeDict: PageNode: %s\n", ir) + + d, err = ctx.DereferenceDict(ir) + if err != nil { + return nil, nil, errors.New("pdfcpu: pageNodeDict: cannot dereference, pageNodeDict") + } + if d == nil { + return nil, nil, errors.New("pdfcpu: pageNodeDict: pageNodeDict is null") + } + + dictType := d.Type() + if dictType == nil { + return nil, nil, errors.New("pdfcpu: pageNodeDict: missing pageNodeDict type") + } + + return d, &ir, nil +} + +func writeKids(ctx *Context, a Array, pageNr *int) (Array, int, error) { + + kids := Array{} + count := 0 + + for _, o := range a { + + d, ir, err := pageNodeDict(ctx, o) + if err != nil { + return nil, 0, err + } + if d == nil { + continue + } + + switch *d.Type() { + + case "Pages": + // Recurse over pagetree + skip, c, err := writePagesDict(ctx, ir, pageNr) + if err != nil { + return nil, 0, err + } + if !skip { + kids = append(kids, o) + count += c + } + + case "Page": + *pageNr++ + if len(ctx.Write.SelectedPages) > 0 { + log.Write.Printf("selectedPages: %v\n", ctx.Write.SelectedPages) + writePage := ctx.Write.SelectedPages[*pageNr] + if ctx.Cmd == REMOVEPAGES { + writePage = !writePage + } + if writePage { + log.Write.Printf("writeKids: writing page:%d\n", *pageNr) + err = writePageDict(ctx, ir, d, *pageNr) + kids = append(kids, o) + count++ + } else { + log.Write.Printf("writeKids: skipping page:%d\n", *pageNr) + } + } else { + log.Write.Printf("writeKids: writing page anyway:%d\n", *pageNr) + err = writePageDict(ctx, ir, d, *pageNr) + kids = append(kids, o) + count++ + } + + default: + err = errors.Errorf("pdfcpu: writeKids: Unexpected dict type: %s", *d.Type()) + + } + + if err != nil { + return nil, 0, err + } + + } + + return kids, count, nil +} + +func containsSelectedPages(ctx *Context, from, thru int) bool { + for i := from; i <= thru; i++ { + if ctx.Write.SelectedPages[i] { + return true + } + } + return false +} + +func writePagesDict(ctx *Context, ir *IndirectRef, pageNr *int) (skip bool, writtenPages int, err error) { + + log.Write.Printf("writePagesDict: begin pageNr=%d\n", *pageNr) + + dictName := "pagesDict" + objNr := int(ir.ObjectNumber) + genNr := int(ir.GenerationNumber) + + d, err := ctx.DereferenceDict(*ir) + if err != nil { + return false, 0, errors.Wrapf(err, "writePagesDict: unable to dereference indirect object #%d", objNr) + } + + // Push count, kids. + countOrig, _ := d.Find("Count") + kidsOrig := d.ArrayEntry("Kids") + + // TRIM, REMOVEPAGES are the only commands where we modify the page tree during writing. + // In these cases the selected pages to be written or to be removed are defined in ctx.Write.SelectedPages. + if len(ctx.Write.SelectedPages) > 0 { + c := int(countOrig.(Integer)) + log.Write.Printf("writePagesDict: checking page range %d - %d \n", *pageNr+1, *pageNr+c) + if ctx.Cmd == REMOVEPAGES || + ((ctx.Cmd == TRIM) && containsSelectedPages(ctx, *pageNr+1, *pageNr+c)) { + log.Write.Println("writePagesDict: process this subtree") + } else { + log.Write.Println("writePagesDict: skip this subtree") + *pageNr += c + return true, 0, nil + } + } + + // Iterate over page tree. + kidsArray := d.ArrayEntry("Kids") + kidsNew, countNew, err := writeKids(ctx, kidsArray, pageNr) + if err != nil { + return false, 0, err + } + + d.Update("Kids", kidsNew) + d.Update("Count", Integer(countNew)) + log.Write.Printf("writePagesDict: writing pageDict for obj=%d page=%d\n%s", objNr, *pageNr, d) + + if err = writeDictObject(ctx, objNr, genNr, d); err != nil { + return false, 0, err + } + + // TODO Check inheritance rules. + for _, e := range []struct { + entryName string + statsAttr int + }{ + {"Resources", PageResources}, + {"MediaBox", PageMediaBox}, + {"CropBox", PageCropBox}, + {"Rotate", PageRotate}, + } { + if err = writePageEntry(ctx, d, dictName, e.entryName, e.statsAttr); err != nil { + return false, 0, err + } + } + + // Pop kids, count. + d.Update("Kids", kidsOrig) + d.Update("Count", countOrig) + + log.Write.Printf("writePagesDict: end pageNr=%d\n", *pageNr) + + return false, countNew, nil +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/writeStats.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/writeStats.go new file mode 100644 index 0000000..bda8d04 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/writeStats.go @@ -0,0 +1,266 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +func logWriteStats(ctx *Context) { + + xRefTable := ctx.XRefTable + + if len(xRefTable.Table) != *xRefTable.Size { + if count, mstr := xRefTable.MissingObjects(); count > 0 { + log.Stats.Printf("%d missing objects: %s\n", count, *mstr) + } + } + + var nonRefObjs []int + + for i := 0; i < *xRefTable.Size; i++ { + + entry, found := xRefTable.Find(i) + if !found || entry.Free || ctx.Write.HasWriteOffset(i) { + continue + } + + nonRefObjs = append(nonRefObjs, i) + + } + + // Non referenced objects + ctx.Optimize.NonReferencedObjs = nonRefObjs + l, str := ctx.Optimize.NonReferencedObjsString() + log.Stats.Printf("%d original empty xref entries:\n%s", l, str) + + // Duplicate font objects + l, str = ctx.Optimize.DuplicateFontObjectsString() + log.Stats.Printf("%d original redundant font entries: %s", l, str) + + // Duplicate image objects + l, str = ctx.Optimize.DuplicateImageObjectsString() + log.Stats.Printf("%d original redundant image entries: %s", l, str) + + // Duplicate info objects + l, str = ctx.Optimize.DuplicateInfoObjectsString() + log.Stats.Printf("%d original redundant info entries: %s", l, str) + + // ObjectStreams + l, str = ctx.Read.ObjectStreamsString() + log.Stats.Printf("%d original objectStream entries: %s", l, str) + + // XRefStreams + l, str = ctx.Read.XRefStreamsString() + log.Stats.Printf("%d original xrefStream entries: %s", l, str) + + // Linearization objects + l, str = ctx.LinearizationObjsString() + log.Stats.Printf("%d original linearization entries: %s", l, str) +} + +func statsHeadLine() *string { + + hl := "name;version;author;creator;producer;src_size (bin|text);src_bin:imgs|fonts|other;dest_size (bin|text);dest_bin:imgs|fonts|other;" + hl += "linearized;hybrid;xrefstr;objstr;pages;objs;missing;garbage;" + hl += "R_Version;R_Extensions;R_PageLabels;R_Names;R_Dests;R_ViewerPrefs;R_PageLayout;R_PageMode;" + hl += "R_Outlines;R_Threads;R_OpenAction;R_AA;R_URI;R_AcroForm;R_Metadata;R_StructTreeRoot;R_MarkInfo;" + hl += "R_Lang;R_SpiderInfo;R_OutputIntents;R_PieceInfo;R_OCProperties;R_Perms;R_Legal;R_Requirements;" + hl += "R_Collection;R_NeedsRendering;" + hl += "P_LastModified;P_Resources;P_MediaBox;P_CropBox;P_BleedBox;P_TrimBox;P_ArtBox;" + hl += "P_BoxColorInfo;P_Contents;P_Rotate;P_Group;P_Thumb;P_B;P_Dur;P_Trans;P_Annots;" + hl += "P_AA;P_Metadata;P_PieceInfo;P_StructParents;P_ID;P_PZ;P_SeparationInfo;P_Tabs;" + hl += "P_TemplateInstantiated;P_PresSteps;P_UserUnit;P_VP;\n" + + return &hl +} + +func statsLine(ctx *Context) *string { + + xRefTable := ctx.XRefTable + + version := xRefTable.HeaderVersion.String() + if xRefTable.RootVersion != nil { + version = fmt.Sprintf("%s,%s", version, xRefTable.RootVersion.String()) + } + + sourceFileSize := ctx.Read.FileSize + sourceBinarySize := ctx.Read.BinaryTotalSize + sourceNonBinarySize := sourceFileSize - sourceBinarySize + + sourceSizeStats := fmt.Sprintf("%s (%4.1f%% | %4.1f%%)", + ByteSize(sourceFileSize), + float32(sourceBinarySize)/float32(sourceFileSize)*100, + float32(sourceNonBinarySize)/float32(sourceFileSize)*100) + + sourceBinaryImageSize := ctx.Read.BinaryImageSize + ctx.Read.BinaryImageDuplSize + sourceBinaryFontSize := ctx.Read.BinaryFontSize + ctx.Read.BinaryFontDuplSize + sourceBinaryOtherSize := sourceBinarySize - sourceBinaryImageSize - sourceBinaryFontSize + + sourceBinaryStats := fmt.Sprintf("%4.1f%% | %4.1f%% | %4.1f%%", + float32(sourceBinaryImageSize)/float32(sourceBinarySize)*100, + float32(sourceBinaryFontSize)/float32(sourceBinarySize)*100, + float32(sourceBinaryOtherSize)/float32(sourceBinarySize)*100) + + destFileSize := ctx.Write.FileSize + destBinarySize := ctx.Write.BinaryTotalSize + destNonBinarySize := destFileSize - destBinarySize + + destSizeStats := fmt.Sprintf("%s (%4.1f%% | %4.1f%%)", + ByteSize(destFileSize), + float32(destBinarySize)/float32(destFileSize)*100, + float32(destNonBinarySize)/float32(destFileSize)*100) + + destBinaryImageSize := ctx.Write.BinaryImageSize + destBinaryFontSize := ctx.Write.BinaryFontSize + destBinaryOtherSize := destBinarySize - destBinaryImageSize - destBinaryFontSize + + destBinaryStats := fmt.Sprintf("%4.1f%% | %4.1f%% | %4.1f%%", + float32(destBinaryImageSize)/float32(destBinarySize)*100, + float32(destBinaryFontSize)/float32(destBinarySize)*100, + float32(destBinaryOtherSize)/float32(destBinarySize)*100) + + var missingObjs string + if count, mstr := xRefTable.MissingObjects(); count > 0 { + missingObjs = fmt.Sprintf("%d:%s", count, *mstr) + } + + var nonreferencedObjs string + if len(ctx.Optimize.NonReferencedObjs) > 0 { + var s []string + for _, o := range ctx.Optimize.NonReferencedObjs { + s = append(s, fmt.Sprintf("%d", o)) + } + nonreferencedObjs = fmt.Sprintf("%d:%s", len(ctx.Optimize.NonReferencedObjs), strings.Join(s, ",")) + } + + line := fmt.Sprintf("%s;%s;%s;%s;%s;%s;%s;%s;%s;%v;%v;%v;%v;%d;%d;%s;%s;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v;%v\n", + filepath.Base(ctx.Read.FileName), + version, + xRefTable.Author, + xRefTable.Creator, + xRefTable.Producer, + sourceSizeStats, + sourceBinaryStats, + destSizeStats, + destBinaryStats, + ctx.Read.Linearized, + ctx.Read.Hybrid, + ctx.Read.UsingXRefStreams, + ctx.Read.UsingObjectStreams, + xRefTable.PageCount, + *xRefTable.Size, + missingObjs, + nonreferencedObjs, + xRefTable.Stats.UsesRootAttr(RootVersion), + xRefTable.Stats.UsesRootAttr(RootExtensions), + xRefTable.Stats.UsesRootAttr(RootPageLabels), + xRefTable.Stats.UsesRootAttr(RootNames), + xRefTable.Stats.UsesRootAttr(RootDests), + xRefTable.Stats.UsesRootAttr(RootViewerPrefs), + xRefTable.Stats.UsesRootAttr(RootPageLayout), + xRefTable.Stats.UsesRootAttr(RootPageMode), + xRefTable.Stats.UsesRootAttr(RootOutlines), + xRefTable.Stats.UsesRootAttr(RootThreads), + xRefTable.Stats.UsesRootAttr(RootOpenAction), + xRefTable.Stats.UsesRootAttr(RootAA), + xRefTable.Stats.UsesRootAttr(RootURI), + xRefTable.Stats.UsesRootAttr(RootAcroForm), + xRefTable.Stats.UsesRootAttr(RootMetadata), + xRefTable.Stats.UsesRootAttr(RootStructTreeRoot), + xRefTable.Stats.UsesRootAttr(RootMarkInfo), + xRefTable.Stats.UsesRootAttr(RootLang), + xRefTable.Stats.UsesRootAttr(RootSpiderInfo), + xRefTable.Stats.UsesRootAttr(RootOutputIntents), + xRefTable.Stats.UsesRootAttr(RootPieceInfo), + xRefTable.Stats.UsesRootAttr(RootOCProperties), + xRefTable.Stats.UsesRootAttr(RootPerms), + xRefTable.Stats.UsesRootAttr(RootLegal), + xRefTable.Stats.UsesRootAttr(RootRequirements), + xRefTable.Stats.UsesRootAttr(RootCollection), + xRefTable.Stats.UsesRootAttr(RootNeedsRendering), + xRefTable.Stats.UsesPageAttr(PageLastModified), + xRefTable.Stats.UsesPageAttr(PageResources), + xRefTable.Stats.UsesPageAttr(PageMediaBox), + xRefTable.Stats.UsesPageAttr(PageCropBox), + xRefTable.Stats.UsesPageAttr(PageBleedBox), + xRefTable.Stats.UsesPageAttr(PageTrimBox), + xRefTable.Stats.UsesPageAttr(PageArtBox), + xRefTable.Stats.UsesPageAttr(PageBoxColorInfo), + xRefTable.Stats.UsesPageAttr(PageContents), + xRefTable.Stats.UsesPageAttr(PageRotate), + xRefTable.Stats.UsesPageAttr(PageGroup), + xRefTable.Stats.UsesPageAttr(PageThumb), + xRefTable.Stats.UsesPageAttr(PageB), + xRefTable.Stats.UsesPageAttr(PageDur), + xRefTable.Stats.UsesPageAttr(PageTrans), + xRefTable.Stats.UsesPageAttr(PageAnnots), + xRefTable.Stats.UsesPageAttr(PageAA), + xRefTable.Stats.UsesPageAttr(PageMetadata), + xRefTable.Stats.UsesPageAttr(PagePieceInfo), + xRefTable.Stats.UsesPageAttr(PageStructParents), + xRefTable.Stats.UsesPageAttr(PageID), + xRefTable.Stats.UsesPageAttr(PagePZ), + xRefTable.Stats.UsesPageAttr(PageSeparationInfo), + xRefTable.Stats.UsesPageAttr(PageTabs), + xRefTable.Stats.UsesPageAttr(PageTemplateInstantiated), + xRefTable.Stats.UsesPageAttr(PagePresSteps), + xRefTable.Stats.UsesPageAttr(PageUserUnit), + xRefTable.Stats.UsesPageAttr(PageVP)) + + return &line +} + +// AppendStatsFile appends a stats line for this xRefTable to the configured csv file name. +func AppendStatsFile(ctx *Context) error { + + fileName := ctx.StatsFileName + + // if file does not exist, create file + file, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, 0600) + if err != nil { + + if os.IsExist(err) { + return errors.Errorf("can't open %s\n%s", fileName, err) + } + + file, err = os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + if err != nil { + return errors.Errorf("can't create %s\n%s", fileName, err) + } + + _, err = file.WriteString(*statsHeadLine()) + if err != nil { + return err + } + + } + + defer func() { + file.Close() + }() + + _, err = file.WriteString(*statsLine(ctx)) + + return err +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/xreftable.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/xreftable.go new file mode 100644 index 0000000..e44417e --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/pdfcpu/xreftable.go @@ -0,0 +1,2369 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pdfcpu + +import ( + "encoding/hex" + "fmt" + "io" + "io/ioutil" + "os" + "path" + "sort" + "strings" + "time" + + "github.com/pdfcpu/pdfcpu/pkg/filter" + "github.com/pdfcpu/pdfcpu/pkg/log" + "github.com/pkg/errors" +) + +// XRefTableEntry represents an entry in the PDF cross reference table. +// +// This may wrap a free object, a compressed object or any in use PDF object: +// +// Dict, StreamDict, ObjectStreamDict, PDFXRefStreamDict, +// Array, Integer, Float, Name, StringLiteral, HexLiteral, Boolean +type XRefTableEntry struct { + Free bool + Offset *int64 + Generation *int + RefCount int + Object Object + Compressed bool + ObjectStream *int + ObjectStreamInd *int + Valid bool +} + +// NewXRefTableEntryGen0 returns a cross reference table entry for an object with generation 0. +func NewXRefTableEntryGen0(obj Object) *XRefTableEntry { + zero := 0 + return &XRefTableEntry{Generation: &zero, Object: obj} +} + +// NewFreeHeadXRefTableEntry returns the xref table entry for object 0 +// which is per definition the head of the free list (list of free objects). +func NewFreeHeadXRefTableEntry() *XRefTableEntry { + + freeHeadGeneration := FreeHeadGeneration + zero := int64(0) + + return &XRefTableEntry{ + Free: true, + Generation: &freeHeadGeneration, + Offset: &zero, + } +} + +// Enc wraps around all defined encryption attributes. +type Enc struct { + O, U []byte + OE, UE []byte + Perms []byte + L, P, R, V int + Emd bool // encrypt meta data + ID []byte +} + +// XRefTable represents a PDF cross reference table plus stats for a PDF file. +type XRefTable struct { + Table map[int]*XRefTableEntry + Size *int // Object count from PDF trailer dict. + PageCount int // Number of pages. + Root *IndirectRef // Pointer to catalog (reference to root object). + RootDict Dict // Catalog + Names map[string]*Node // Cache for name trees as found in catalog. + Encrypt *IndirectRef // Encrypt dict. + E *Enc + EncKey []byte // Encrypt key. + AES4Strings bool + AES4Streams bool + AES4EmbeddedStreams bool + + // PDF Version + HeaderVersion *Version // The PDF version the source is claiming to us as per its header. + RootVersion *Version // Optional PDF version taking precedence over the header version. + + // Document information section + ID Array // from trailer + Info *IndirectRef // Infodict (reference to info dict object) + Title string + Subject string + Keywords string + Author string + Creator string + Producer string + CreationDate string + ModDate string + Properties map[string]string + + // Linearization section (not yet supported) + OffsetPrimaryHintTable *int64 + OffsetOverflowHintTable *int64 + LinearizationObjs IntSet + + // Offspec section + AdditionalStreams *Array // array of IndirectRef - trailer :e.g., Oasis "Open Doc" + + // Statistics + Stats PDFStats + + Tagged bool // File is using tags. This is important for ??? + + // Validation + Valid bool // true means successful validated against ISO 32000. + ValidationMode int // see Configuration + + Optimized bool + Watermarked bool +} + +// NewXRefTable creates a new XRefTable. +func newXRefTable(validationMode int) (xRefTable *XRefTable) { + return &XRefTable{ + Table: map[int]*XRefTableEntry{}, + Names: map[string]*Node{}, + Properties: map[string]string{}, + LinearizationObjs: IntSet{}, + Stats: NewPDFStats(), + ValidationMode: validationMode, + } +} + +// Version returns the PDF version of the PDF writer that created this file. +// Before V1.4 this is the header version. +// Since V1.4 the catalog may contain a Version entry which takes precedence over the header version. +func (xRefTable *XRefTable) Version() Version { + + if xRefTable.RootVersion != nil { + return *xRefTable.RootVersion + } + + return *xRefTable.HeaderVersion +} + +// VersionString return a string representation for this PDF files PDF version. +func (xRefTable *XRefTable) VersionString() string { + return xRefTable.Version().String() +} + +// ParseRootVersion returns a string representation for an optional Version entry in the root object. +func (xRefTable *XRefTable) ParseRootVersion() (v *string, err error) { + + // Look in the catalog/root for a name entry "Version". + // This entry overrides the header version. + + rootDict, err := xRefTable.Catalog() + if err != nil { + return nil, err + } + + return rootDict.NameEntry("Version"), nil +} + +// ValidateVersion validates against the xRefTable's version. +func (xRefTable *XRefTable) ValidateVersion(element string, sinceVersion Version) error { + + if xRefTable.Version() < sinceVersion { + return errors.Errorf("%s: unsupported in version %s\nThis file could be PDF/A compliant but pdfcpu only supports versions <= PDF V1.7\n", element, xRefTable.VersionString()) + } + + return nil +} + +// EnsureVersionForWriting sets the version to the highest supported PDF Version 1.7. +// This is necessary to allow validation after adding features not supported +// by the original version of a document as during watermarking. +func (xRefTable *XRefTable) EnsureVersionForWriting() { + v := V17 + xRefTable.RootVersion = &v +} + +// IsLinearizationObject returns true if object #i is a a linearization object. +func (xRefTable *XRefTable) IsLinearizationObject(i int) bool { + return xRefTable.LinearizationObjs[i] +} + +// LinearizationObjsString returns a formatted string and the number of objs. +func (xRefTable *XRefTable) LinearizationObjsString() (int, string) { + + var objs []int + for k := range xRefTable.LinearizationObjs { + if xRefTable.LinearizationObjs[k] { + objs = append(objs, k) + } + } + sort.Ints(objs) + + var linObj []string + for _, i := range objs { + linObj = append(linObj, fmt.Sprintf("%d", i)) + } + + return len(linObj), strings.Join(linObj, ",") +} + +// Exists returns true if xRefTable contains an entry for objNumber. +func (xRefTable *XRefTable) Exists(objNr int) bool { + _, found := xRefTable.Table[objNr] + return found +} + +// Find returns the XRefTable entry for given object number. +func (xRefTable *XRefTable) Find(objNr int) (*XRefTableEntry, bool) { + e, found := xRefTable.Table[objNr] + if !found { + return nil, false + } + return e, true +} + +// FindObject returns the object of the XRefTableEntry for a specific object number. +func (xRefTable *XRefTable) FindObject(objNr int) (Object, error) { + entry, ok := xRefTable.Find(objNr) + if !ok { + return nil, errors.Errorf("FindObject: obj#%d not registered in xRefTable", objNr) + } + return entry.Object, nil +} + +// Free returns the cross ref table entry for given number of a free object. +func (xRefTable *XRefTable) Free(objNr int) (*XRefTableEntry, error) { + entry, found := xRefTable.Find(objNr) + if !found { + return nil, nil //errors.Errorf("Free: object #%d not found.", objNr) + } + if !entry.Free { + return nil, errors.Errorf("Free: object #%d found, but not free.", objNr) + } + return entry, nil +} + +// NextForFree returns the number of the object the free object with objNumber links to. +// This is the successor of this free object in the free list. +func (xRefTable *XRefTable) NextForFree(objNr int) (int, error) { + + entry, err := xRefTable.Free(objNr) + if err != nil { + return 0, err + } + + return int(*entry.Offset), nil +} + +// FindTableEntryLight returns the XRefTable entry for given object number. +func (xRefTable *XRefTable) FindTableEntryLight(objNr int) (*XRefTableEntry, bool) { + return xRefTable.Find(objNr) +} + +// FindTableEntry returns the XRefTable entry for given object and generation numbers. +func (xRefTable *XRefTable) FindTableEntry(objNr int, genNr int) (*XRefTableEntry, bool) { + + //fmt.Printf("FindTableEntry: obj#:%d gen:%d \n", objNr, genNr) + entry, found := xRefTable.Find(objNr) + if !found || *entry.Generation != genNr { + return nil, false + } + return entry, found +} + +// FindTableEntryForIndRef returns the XRefTable entry for given indirect reference. +func (xRefTable *XRefTable) FindTableEntryForIndRef(ir *IndirectRef) (*XRefTableEntry, bool) { + if ir == nil { + return nil, false + } + return xRefTable.FindTableEntry(ir.ObjectNumber.Value(), ir.GenerationNumber.Value()) +} + +// InsertNew adds given xRefTableEntry at next new objNumber into the cross reference table. +// Only to be called once an xRefTable has been generated completely and all trailer dicts have been processed. +// xRefTable.Size is the size entry of the first trailer dict processed. +// Called on creation of new object streams. +// Called by InsertAndUseRecycled. +func (xRefTable *XRefTable) InsertNew(xRefTableEntry XRefTableEntry) (objNr int) { + objNr = *xRefTable.Size + xRefTable.Table[objNr] = &xRefTableEntry + *xRefTable.Size++ + return +} + +// InsertAndUseRecycled adds given xRefTableEntry into the cross reference table utilizing the freelist. +func (xRefTable *XRefTable) InsertAndUseRecycled(xRefTableEntry XRefTableEntry) (objNr int, err error) { + + // see 7.5.4 Cross-Reference Table + + // Hacky: + // Although we increment the obj generation when recycling objects, + // we always use generation 0 when reusing recycled objects. + // This is because pdfcpu does not reuse objects + // in an incremental fashion like laid out in the PDF spec. + + log.Write.Println("InsertAndUseRecycled: begin") + + // Get Next free object from freelist. + freeListHeadEntry, err := xRefTable.Free(0) + if err != nil { + return 0, err + } + + // If none available, add new object & return. + if *freeListHeadEntry.Offset == 0 { + xRefTableEntry.RefCount = 1 + objNr = xRefTable.InsertNew(xRefTableEntry) + log.Write.Printf("InsertAndUseRecycled: end, new objNr=%d\n", objNr) + return objNr, nil + } + + // Recycle free object, update free list & return. + objNr = int(*freeListHeadEntry.Offset) + entry, found := xRefTable.FindTableEntryLight(objNr) + if !found { + return 0, errors.Errorf("InsertAndRecycle: no entry for obj #%d\n", objNr) + } + + // The new free list head entry becomes the old head entry's successor. + freeListHeadEntry.Offset = entry.Offset + + // The old head entry becomes garbage. + entry.Free = false + entry.Offset = nil + + // Create a new entry for the recycled object. + // TODO use entrys generation. + xRefTableEntry.RefCount = 1 + xRefTable.Table[objNr] = &xRefTableEntry + + log.Write.Printf("InsertAndUseRecycled: end, recycled objNr=%d\n", objNr) + + return objNr, nil +} + +// InsertObject inserts an object into the xRefTable. +func (xRefTable *XRefTable) InsertObject(obj Object) (objNr int, err error) { + xRefTableEntry := NewXRefTableEntryGen0(obj) + xRefTableEntry.RefCount = 1 + return xRefTable.InsertNew(*xRefTableEntry), nil +} + +// IndRefForNewObject inserts an object into the xRefTable and returns an indirect reference to it. +func (xRefTable *XRefTable) IndRefForNewObject(obj Object) (*IndirectRef, error) { + xRefTableEntry := NewXRefTableEntryGen0(obj) + objNr, err := xRefTable.InsertAndUseRecycled(*xRefTableEntry) + if err != nil { + return nil, err + } + + return NewIndirectRef(objNr, *xRefTableEntry.Generation), nil +} + +// NewStreamDictForBuf creates a streamDict for buf. +func (xRefTable *XRefTable) NewStreamDictForBuf(buf []byte) (*StreamDict, error) { + sd := StreamDict{ + Dict: NewDict(), + Content: buf, + FilterPipeline: []PDFFilter{{Name: filter.Flate, DecodeParms: nil}}, + } + sd.InsertName("Filter", filter.Flate) + return &sd, nil +} + +// NewStreamDictForFile creates a streamDict for filename. +func (xRefTable *XRefTable) NewStreamDictForFile(filename string) (*StreamDict, error) { + buf, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + + return xRefTable.NewStreamDictForBuf(buf) +} + +// NewEmbeddedStreamDict creates and returns an embeddedStreamDict containing the bytes represented by r. +func (xRefTable *XRefTable) NewEmbeddedStreamDict(r io.Reader, modDate time.Time) (*IndirectRef, error) { + buf, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + sd, err := xRefTable.NewStreamDictForBuf(buf) + if err != nil { + return nil, err + } + + sd.InsertName("Type", "EmbeddedFile") + d := NewDict() + d.InsertInt("Size", len(buf)) + d.Insert("ModDate", StringLiteral(DateString(modDate))) + sd.Insert("Params", d) + if err = sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +// NewFileSpectDictForAttachment returns a fileSpecDict for a. +func (xRefTable *XRefTable) NewFileSpectDictForAttachment(a Attachment) (*IndirectRef, error) { + modTime := time.Now() + if a.ModTime != nil { + modTime = *a.ModTime + } + sd, err := xRefTable.NewEmbeddedStreamDict(a, modTime) + if err != nil { + return nil, err + } + + d, err := xRefTable.NewFileSpecDict(a.ID, encodeUTF16String(a.ID), a.Desc, *sd) + if err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(d) +} + +// NewEmbeddedFileStreamDict returns an embeddedFileStreamDict containing the file "filename". +func (xRefTable *XRefTable) NewEmbeddedFileStreamDict(filename string) (*IndirectRef, error) { + f, err := os.Open(filename) + if err != nil { + return nil, err + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + return nil, err + } + + return xRefTable.NewEmbeddedStreamDict(f, fi.ModTime()) +} + +// NewSoundStreamDict returns a new sound stream dict. +func (xRefTable *XRefTable) NewSoundStreamDict(filename string, samplingRate int, fileSpecDict Dict) (*IndirectRef, error) { + sd, err := xRefTable.NewStreamDictForFile(filename) + if err != nil { + return nil, err + } + sd.InsertName("Type", "Sound") + sd.InsertInt("R", samplingRate) + sd.InsertInt("C", 2) + sd.InsertInt("B", 8) + sd.InsertName("E", "Signed") + if fileSpecDict != nil { + sd.Insert("F", fileSpecDict) + } else { + sd.Insert("F", StringLiteral(path.Base(filename))) + } + + if err = sd.Encode(); err != nil { + return nil, err + } + + return xRefTable.IndRefForNewObject(*sd) +} + +// NewFileSpecDict creates and returns a new fileSpec dictionary. +func (xRefTable *XRefTable) NewFileSpecDict(f, uf, desc string, indRefStreamDict IndirectRef) (Dict, error) { + + d := NewDict() + d.InsertName("Type", "Filespec") + d.InsertString("F", f) + d.InsertString("UF", uf) + + efDict := NewDict() + efDict.Insert("F", indRefStreamDict) + efDict.Insert("UF", indRefStreamDict) + d.Insert("EF", efDict) + + d.InsertString("Desc", desc) + + // CI, optional, collection item dict, since V1.7 + // a corresponding collection schema dict in a collection. + ciDict := NewDict() + //add contextual meta info here. + d.Insert("CI", ciDict) + + return d, nil +} + +func (xRefTable *XRefTable) freeObjects() IntSet { + + m := IntSet{} + + for k, v := range xRefTable.Table { + if v.Free && k > 0 { + m[k] = true + } + } + + return m +} + +// EnsureValidFreeList ensures the integrity of the free list associated with the recorded free objects. +// See 7.5.4 Cross-Reference Table +func (xRefTable *XRefTable) EnsureValidFreeList() error { + + log.Trace.Println("EnsureValidFreeList begin") + + m := xRefTable.freeObjects() + + // Verify free object 0 as free list head. + head, err := xRefTable.Free(0) + if err != nil { + return err + } + + if head == nil { + g0 := FreeHeadGeneration + z := int64(0) + head = &XRefTableEntry{Free: true, Offset: &z, Generation: &g0} + xRefTable.Table[0] = head + } + + // verify generation of 56535 + if *head.Generation != FreeHeadGeneration { + // Fix generation for obj 0. + *head.Generation = FreeHeadGeneration + } + + if len(m) == 0 { + + // no free object other than 0. + + // repair if necessary + if *head.Offset != 0 { + *head.Offset = 0 + } + + log.Trace.Println("EnsureValidFreeList: empty free list.") + return nil + } + + e := head + f := int(*e.Offset) + + // until we have found the last free object which should point to obj 0. + for f != 0 { + + log.Trace.Printf("EnsureValidFreeList: validating obj #%d %v\n", f, m) + // verify if obj f is one of the free objects recorded. + if !m[f] { + if len(m) > 0 { + return errors.New("pdfcpu: ensureValidFreeList: freelist corrupted") + } + // Repair last entry. + *e.Offset = 0 + break + } + + delete(m, f) + + e, err = xRefTable.Free(f) + if err != nil { + return err + } + + f = int(*e.Offset) + } + + if len(m) == 0 { + log.Trace.Println("EnsureValidFreeList: end, regular linked list") + return nil + } + + // insert remaining free objects into verified linked list + // unless they are forever deleted with generation 65535. + // In that case they have to point to obj 0. + for i := range m { + + entry, found := xRefTable.FindTableEntryLight(i) + if !found { + return errors.Errorf("pdfcpu: ensureValidFreeList: no xref entry found for obj #%d\n", i) + } + + if !entry.Free { + return errors.Errorf("pdfcpu: ensureValidFreeList: xref entry is not free for obj #%d\n", i) + } + + if *entry.Generation == FreeHeadGeneration { + zero := int64(0) + entry.Offset = &zero + continue + } + + entry.Offset = head.Offset + next := int64(i) + head.Offset = &next + } + + log.Trace.Println("EnsureValidFreeList: end, linked list plus some dangling free objects.") + + return nil +} + +func (xRefTable *XRefTable) deleteDictEntry(d Dict, key string) error { + o, found := d.Find(key) + if !found { + return nil + } + if err := xRefTable.deleteObject(o); err != nil { + return err + } + d.Delete(key) + return nil +} + +func (xRefTable *XRefTable) locateObjForIndRef(ir IndirectRef) (Object, error) { + + var err error + objNr := int(ir.ObjectNumber) + + entry, found := xRefTable.FindTableEntryLight(objNr) + if !found { + return nil, errors.Errorf("pdfcpu: locateObjForIndRef: no xref entry found for obj #%d\n", objNr) + } + + if entry.RefCount > 1 { + entry.RefCount-- + //fmt.Printf("locateObjForIndRef(%d): new refcount: %d\n", objNr, entry.RefCount) + return nil, nil + } + + o, err := xRefTable.Dereference(ir) + if err != nil || o == nil { + return o, err + } + + if err = xRefTable.DeleteObject(objNr); err != nil { + return nil, err + } + + return o, nil +} + +func (xRefTable *XRefTable) deleteObject(o Object) error { + + var err error + + ir, ok := o.(IndirectRef) + if ok { + o, err = xRefTable.locateObjForIndRef(ir) + if err != nil || o == nil { + return err + } + } + + switch o := o.(type) { + + case Dict: + for _, v := range o { + err := xRefTable.deleteObject(v) + if err != nil { + return err + } + } + + case StreamDict: + for _, v := range o.Dict { + err := xRefTable.deleteObject(v) + if err != nil { + return err + } + } + + case Array: + for _, v := range o { + err := xRefTable.deleteObject(v) + if err != nil { + return err + } + } + + } + + return nil +} + +// DeleteObjectGraph deletes all objects reachable by indRef. +func (xRefTable *XRefTable) DeleteObjectGraph(o Object) error { + + log.Debug.Println("DeleteObjectGraph: begin") + + ir, ok := o.(IndirectRef) + if !ok { + return nil + } + + // Delete ObjectGraph for object indRef.ObjectNumber.Value() via recursion. + if err := xRefTable.deleteObject(ir); err != nil { + return err + } + + log.Debug.Println("DeleteObjectGraph: end") + return nil +} + +// DeleteObject marks an object as free and inserts it into the free list right after the head. +func (xRefTable *XRefTable) DeleteObject(objNr int) error { + + // see 7.5.4 Cross-Reference Table + + log.Debug.Printf("DeleteObject: begin %d\n", objNr) + + freeListHeadEntry, err := xRefTable.Free(0) + if err != nil { + return err + } + + entry, found := xRefTable.FindTableEntryLight(objNr) + if !found { + return errors.Errorf("pdfcpu: deleteObject: no entry for obj #%d\n", objNr) + } + + if entry.Free { + log.Debug.Printf("DeleteObject: end %d already free\n", objNr) + return nil + } + + *entry.Generation++ + entry.Free = true + entry.Compressed = false + entry.Offset = freeListHeadEntry.Offset + entry.Object = nil + entry.RefCount = 0 + + next := int64(objNr) + freeListHeadEntry.Offset = &next + + log.Debug.Printf("DeleteObject: end %d\n", objNr) + + return nil +} + +// UndeleteObject ensures an object is not recorded in the free list. +// e.g. sometimes caused by indirect references to free objects in the original PDF file. +func (xRefTable *XRefTable) UndeleteObject(objectNumber int) error { + + log.Debug.Printf("UndeleteObject: begin %d\n", objectNumber) + + f, err := xRefTable.Free(0) + if err != nil { + return err + } + + // until we have found the last free object which should point to obj 0. + for *f.Offset != 0 { + objNr := int(*f.Offset) + + entry, err := xRefTable.Free(objNr) + if err != nil { + return err + } + + if objNr == objectNumber { + log.Debug.Printf("UndeleteObject end: undeleting obj#%d\n", objectNumber) + *f.Offset = *entry.Offset + entry.Offset = nil + if *entry.Generation > 0 { + *entry.Generation-- + } + entry.Free = false + return nil + } + + f = entry + } + + log.Debug.Printf("UndeleteObject: end: obj#%d not in free list.\n", objectNumber) + + return nil +} + +// indRefToObject dereferences an indirect object from the xRefTable and returns the result. +func (xRefTable *XRefTable) indRefToObject(ir *IndirectRef) (Object, error) { + if ir == nil { + return nil, errors.New("pdfcpu: indRefToObject: input argument is nil") + } + + // 7.3.10 + // An indirect reference to an undefined object shall not be considered an error by a conforming reader; + // it shall be treated as a reference to the null object. + entry, found := xRefTable.FindTableEntryForIndRef(ir) + if !found || entry.Free { + return nil, nil + } + + // return dereferenced object + return entry.Object, nil +} + +// Dereference resolves an indirect object and returns the resulting PDF object. +func (xRefTable *XRefTable) Dereference(o Object) (Object, error) { + ir, ok := o.(IndirectRef) + if !ok { + // Nothing do dereference. + return o, nil + } + + return xRefTable.indRefToObject(&ir) +} + +// DereferenceBoolean resolves and validates a boolean object, which may be an indirect reference. +func (xRefTable *XRefTable) DereferenceBoolean(o Object, sinceVersion Version) (*Boolean, error) { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return nil, err + } + + b, ok := o.(Boolean) + if !ok { + return nil, errors.Errorf("pdfcpu: dereferenceBoolean: wrong type <%v>", o) + } + + // Version check + if err = xRefTable.ValidateVersion("DereferenceBoolean", sinceVersion); err != nil { + return nil, err + } + + return &b, nil +} + +// DereferenceInteger resolves and validates an integer object, which may be an indirect reference. +func (xRefTable *XRefTable) DereferenceInteger(o Object) (*Integer, error) { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return nil, err + } + + i, ok := o.(Integer) + if !ok { + return nil, errors.Errorf("pdfcpu: dereferenceInteger: wrong type <%v>", o) + } + + return &i, nil +} + +// DereferenceNumber resolves a number object, which may be an indirect reference and returns a float64. +func (xRefTable *XRefTable) DereferenceNumber(o Object) (float64, error) { + + var ( + f float64 + err error + ) + + o, _ = xRefTable.Dereference(o) + + switch o := o.(type) { + + case Integer: + f = float64(o.Value()) + + case Float: + f = o.Value() + + default: + err = errors.Errorf("pdfcpu: dereferenceNumber: wrong type <%v>", o) + + } + + return f, err +} + +// DereferenceName resolves and validates a name object, which may be an indirect reference. +func (xRefTable *XRefTable) DereferenceName(o Object, sinceVersion Version, validate func(string) bool) (n Name, err error) { + + o, err = xRefTable.Dereference(o) + if err != nil || o == nil { + return n, err + } + + n, ok := o.(Name) + if !ok { + return n, errors.Errorf("pdfcpu: dereferenceName: wrong type <%v>", o) + } + + // Version check + if err = xRefTable.ValidateVersion("DereferenceName", sinceVersion); err != nil { + return n, err + } + + // Validation + if validate != nil && !validate(n.Value()) { + return n, errors.Errorf("pdfcpu: dereferenceName: invalid <%s>", n.Value()) + } + + return n, nil +} + +// DereferenceStringLiteral resolves and validates a string literal object, which may be an indirect reference. +func (xRefTable *XRefTable) DereferenceStringLiteral(o Object, sinceVersion Version, validate func(string) bool) (s StringLiteral, err error) { + + o, err = xRefTable.Dereference(o) + if err != nil || o == nil { + return s, err + } + + s, ok := o.(StringLiteral) + if !ok { + return s, errors.Errorf("pdfcpu: dereferenceStringLiteral: wrong type <%v>", o) + } + + // Ensure UTF16 correctness. + s1, err := StringLiteralToString(s.Value()) + if err != nil { + return s, err + } + + // Version check + if err = xRefTable.ValidateVersion("DereferenceStringLiteral", sinceVersion); err != nil { + return s, err + } + + // Validation + if validate != nil && !validate(s1) { + return s, errors.Errorf("pdfcpu: dereferenceStringLiteral: invalid <%s>", s1) + } + + return s, nil +} + +// DereferenceStringOrHexLiteral resolves and validates a string or hex literal object, which may be an indirect reference. +func (xRefTable *XRefTable) DereferenceStringOrHexLiteral(obj Object, sinceVersion Version, validate func(string) bool) (s string, err error) { + + o, err := xRefTable.Dereference(obj) + if err != nil || o == nil { + return "", err + } + + switch str := o.(type) { + + case StringLiteral: + // Ensure UTF16 correctness. + if s, err = StringLiteralToString(str.Value()); err != nil { + return "", err + } + + case HexLiteral: + // Ensure UTF16 correctness. + if s, err = HexLiteralToString(str.Value()); err != nil { + return "", err + } + + default: + return "", errors.Errorf("pdfcpu: dereferenceStringOrHexLiteral: wrong type <%v>", obj) + + } + + // Version check + if err = xRefTable.ValidateVersion("DereferenceStringOrHexLiteral", sinceVersion); err != nil { + return "", err + } + + // Validation + if validate != nil && !validate(s) { + return "", errors.Errorf("pdfcpu: dereferenceStringOrHexLiteral: invalid <%s>", s) + } + + return s, nil +} + +// Text returns a string based representation for String and Hexliterals. +func Text(o Object) (string, error) { + switch obj := o.(type) { + case StringLiteral: + return StringLiteralToString(obj.Value()) + case HexLiteral: + return HexLiteralToString(obj.Value()) + default: + return "", errors.Errorf("pdfcpu: text: corrupt - %v\n", obj) + } +} + +// DereferenceText resolves and validates a string or hex literal object to a string. +func (xRefTable *XRefTable) DereferenceText(o Object) (string, error) { + o, err := xRefTable.Dereference(o) + if err != nil { + return "", err + } + return Text(o) +} + +// DereferenceCSVSafeText resolves and validates a string or hex literal object to a string. +func (xRefTable *XRefTable) DereferenceCSVSafeText(o Object) (string, error) { + s, err := xRefTable.DereferenceText(o) + if err != nil { + return "", err + } + return csvSafeString(s), nil +} + +// DereferenceArray resolves and validates an array object, which may be an indirect reference. +func (xRefTable *XRefTable) DereferenceArray(o Object) (Array, error) { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return nil, err + } + + a, ok := o.(Array) + if ok { + return a, nil + } + + d, ok := o.(Dict) + if !ok { + return nil, errors.Errorf("pdfcpu: dereferenceArray: dest of wrong type <%v>", o) + } + + return d["D"].(Array), nil +} + +// DereferenceDict resolves and validates a dictionary object, which may be an indirect reference. +func (xRefTable *XRefTable) DereferenceDict(o Object) (Dict, error) { + + o, err := xRefTable.Dereference(o) + if err != nil || o == nil { + return nil, err + } + + d, ok := o.(Dict) + if !ok { + return nil, errors.Errorf("pdfcpu: dereferenceDict: wrong type %T <%v>", o, o) + } + + return d, nil +} + +// IsValid returns true if the object referenced by ir has already been validated. +func (xRefTable *XRefTable) IsValid(ir IndirectRef) (bool, error) { + entry, found := xRefTable.FindTableEntry(ir.ObjectNumber.Value(), ir.GenerationNumber.Value()) + if !found { + return false, errors.Errorf("pdfcpu: IsValid: no entry for obj#%d\n", ir.ObjectNumber.Value()) + } + // if entry.Object == nil { + // return false, errors.Errorf("pdfcpu: IsValid: no entry for obj#%d\n", ir.ObjectNumber.Value()) + // } + if entry.Free { + return false, errors.Errorf("pdfcpu: IsValid: unexpected free entry for obj#%d\n", ir.ObjectNumber.Value()) + } + return entry.Valid, nil +} + +// SetValid marks the xreftable entry of the object referenced by ir as valid. +func (xRefTable *XRefTable) SetValid(ir IndirectRef) error { + entry, found := xRefTable.FindTableEntry(ir.ObjectNumber.Value(), ir.GenerationNumber.Value()) + if !found { + return errors.Errorf("pdfcpu: SetValid: no entry for obj#%d\n", ir.ObjectNumber.Value()) + } + // if entry.Object == nil { + // return errors.Errorf("pdfcpu: SetValid: no entry for obj#%d\n", ir.ObjectNumber.Value()) + // } + if entry.Free { + return errors.Errorf("pdfcpu: SetValid: unexpected free entry for obj#%d\n", ir.ObjectNumber.Value()) + } + entry.Valid = true + return nil +} + +// DereferenceStreamDict resolves stream dictionary objects. +func (xRefTable *XRefTable) DereferenceStreamDict(o Object) (*StreamDict, bool, error) { + ir, ok := o.(IndirectRef) + if !ok { + sd, ok := o.(StreamDict) + if !ok { + return nil, false, errors.Errorf("pdfcpu: DereferenceStreamDict: wrong type <%v> %T", o, o) + } + return &sd, false, nil + } + + // 7.3.10 + // An indirect reference to an undefined object shall not be considered an error by a conforming reader; + // it shall be treated as a reference to the null object. + entry, found := xRefTable.FindTableEntry(ir.ObjectNumber.Value(), ir.GenerationNumber.Value()) + if !found || entry.Object == nil || entry.Free { + return nil, false, nil + } + ev := entry.Valid + if !entry.Valid { + entry.Valid = true + } + sd, ok := entry.Object.(StreamDict) + if !ok { + return nil, false, errors.Errorf("pdfcpu: DereferenceStreamDict: wrong type <%v> %T", o, entry.Object) + } + + return &sd, ev, nil +} + +// DereferenceDictEntry returns a dereferenced dict entry. +func (xRefTable *XRefTable) DereferenceDictEntry(d Dict, entryName string) (Object, error) { + + o, found := d.Find(entryName) + if !found || o == nil { + return nil, errors.Errorf("pdfcpu: dict=%s entry=%s missing.", d, entryName) + } + + return xRefTable.Dereference(o) +} + +// Catalog returns a pointer to the root object / catalog. +func (xRefTable *XRefTable) Catalog() (Dict, error) { + + if xRefTable.RootDict != nil { + return xRefTable.RootDict, nil + } + + if xRefTable.Root == nil { + return nil, errors.New("pdfcpu: Catalog: missing root dict") + } + + o, err := xRefTable.indRefToObject(xRefTable.Root) + if err != nil || o == nil { + return nil, err + } + + d, ok := o.(Dict) + if !ok { + return nil, errors.New("pdfcpu: catalog: corrupt root catalog") + } + + xRefTable.RootDict = d + + return xRefTable.RootDict, nil +} + +// EncryptDict returns a pointer to the root object / catalog. +func (xRefTable *XRefTable) EncryptDict() (Dict, error) { + + o, err := xRefTable.indRefToObject(xRefTable.Encrypt) + if err != nil || o == nil { + return nil, err + } + + d, ok := o.(Dict) + if !ok { + return nil, errors.New("pdfcpu: encryptDict: corrupt encrypt dict") + } + + return d, nil +} + +// CatalogHasPieceInfo returns true if the root has an entry for \"PieceInfo\". +func (xRefTable *XRefTable) CatalogHasPieceInfo() (bool, error) { + rootDict, err := xRefTable.Catalog() + if err != nil { + return false, err + } + obj, hasPieceInfo := rootDict.Find("PieceInfo") + return hasPieceInfo && obj != nil, nil +} + +// Pages returns the Pages reference contained in the catalog. +func (xRefTable *XRefTable) Pages() (*IndirectRef, error) { + rootDict, err := xRefTable.Catalog() + if err != nil { + return nil, err + } + return rootDict.IndirectRefEntry("Pages"), nil +} + +// Outlines returns the Outlines reference contained in the catalog. +func (xRefTable *XRefTable) Outlines() (*IndirectRef, error) { + rootDict, err := xRefTable.Catalog() + if err != nil { + return nil, err + } + return rootDict.IndirectRefEntry("Outlines"), nil +} + +// MissingObjects returns the number of objects that were not written +// plus the corresponding comma separated string representation. +func (xRefTable *XRefTable) MissingObjects() (int, *string) { + + var missing []string + + for i := 0; i < *xRefTable.Size; i++ { + if !xRefTable.Exists(i) { + missing = append(missing, fmt.Sprintf("%d", i)) + } + } + + var s *string + + if len(missing) > 0 { + joined := strings.Join(missing, ",") + s = &joined + } + + return len(missing), s +} + +func (xRefTable *XRefTable) list(logStr []string) []string { + + var keys []int + for k := range xRefTable.Table { + keys = append(keys, k) + } + sort.Ints(keys) + + // Print list of XRefTable entries to logString. + for _, k := range keys { + + entry := xRefTable.Table[k] + + var str string + + if entry.Free { + str = fmt.Sprintf("%5d: f next=%8d generation=%d\n", k, *entry.Offset, *entry.Generation) + } else if entry.Compressed { + str = fmt.Sprintf("%5d: c => obj:%d[%d] generation=%d \n%s\n", k, *entry.ObjectStream, *entry.ObjectStreamInd, *entry.Generation, entry.Object) + } else { + if entry.Object != nil { + + typeStr := fmt.Sprintf("%T", entry.Object) + + d, ok := entry.Object.(Dict) + + if ok { + if d.Type() != nil { + typeStr += fmt.Sprintf(" type=%s", *d.Type()) + } + if d.Subtype() != nil { + typeStr += fmt.Sprintf(" subType=%s", *d.Subtype()) + } + } + + if entry.ObjectStream != nil { + // was compressed, offset is nil. + str = fmt.Sprintf("%5d: was compressed %d[%d] generation=%d %s \n%s\n", + k, *entry.ObjectStream, *entry.ObjectStreamInd, *entry.Generation, typeStr, entry.Object) + } else { + // regular in use object with offset. + if entry.Offset != nil { + str = fmt.Sprintf("%5d: offset=%8d generation=%d %s \n%s\n", + k, *entry.Offset, *entry.Generation, typeStr, entry.Object) + } else { + str = fmt.Sprintf("%5d: offset=nil generation=%d %s \n%s\n", + k, *entry.Generation, typeStr, entry.Object) + } + + } + + sd, ok := entry.Object.(StreamDict) + if ok && log.IsTraceLoggerEnabled() { //&& sd.IsPageContent { + s := "decoded stream content (length = %d)\n<%s>\n" + if sd.IsPageContent { + str += fmt.Sprintf(s, len(sd.Content), sd.Content) + } else { + str += fmt.Sprintf(s, len(sd.Content), hex.Dump(sd.Content)) + } + } + + osd, ok := entry.Object.(ObjectStreamDict) + if ok { + str += fmt.Sprintf("object stream count:%d size of objectarray:%d\n", osd.ObjCount, len(osd.ObjArray)) + } + + } else { + + str = fmt.Sprintf("%5d: offset=%8d generation=%d nil\n", k, *entry.Offset, *entry.Generation) + } + } + + logStr = append(logStr, str) + } + + return logStr +} + +// Dump the free list to logStr. +// At this point the free list is assumed to be a linked list with its last node linked to the beginning. +func (xRefTable *XRefTable) freeList(logStr []string) ([]string, error) { + + log.Trace.Printf("freeList begin") + + head, err := xRefTable.Free(0) + if err != nil { + return nil, err + } + + if *head.Offset == 0 { + return append(logStr, "\nEmpty free list.\n"), nil + } + + f := int(*head.Offset) + + logStr = append(logStr, "\nfree list:\n obj next generation\n") + logStr = append(logStr, fmt.Sprintf("%5d %5d %5d\n", 0, f, FreeHeadGeneration)) + + for f != 0 { + + log.Trace.Printf("freeList validating free object %d\n", f) + + entry, err := xRefTable.Free(f) + if err != nil { + return nil, err + } + + next := int(*entry.Offset) + generation := *entry.Generation + s := fmt.Sprintf("%5d %5d %5d\n", f, next, generation) + logStr = append(logStr, s) + log.Trace.Printf("freeList: %s", s) + + f = next + } + + log.Trace.Printf("freeList end") + + return logStr, nil +} + +func (xRefTable *XRefTable) bindNameTreeNode(name string, n *Node, root bool) error { + + var dict Dict + + if n.D == nil { + dict = NewDict() + n.D = dict + } else { + if root { + // Update root object after possible tree modification after removal of empty kid. + namesDict, err := xRefTable.NamesDict() + if err != nil { + return err + } + if namesDict == nil { + return errors.New("pdfcpu: root entry \"Names\" corrupt") + } + namesDict.Update(name, n.D) + } + log.Debug.Printf("bind dict = %v\n", n.D) + dict = n.D + } + + if !root { + dict.Update("Limits", NewStringArray(n.Kmin, n.Kmax)) + } else { + dict.Delete("Limits") + } + + if n.leaf() { + a := Array{} + for _, e := range n.Names { + a = append(a, StringLiteral(e.k)) + a = append(a, e.v) + } + dict.Update("Names", a) + log.Debug.Printf("bound nametree node(leaf): %s/n", dict) + return nil + } + + kids := Array{} + for _, k := range n.Kids { + err := xRefTable.bindNameTreeNode(name, k, false) + if err != nil { + return err + } + indRef, err := xRefTable.IndRefForNewObject(k.D) + if err != nil { + return err + } + kids = append(kids, *indRef) + } + + dict.Update("Kids", kids) + dict.Delete("Names") + + log.Debug.Printf("bound nametree node(intermediary): %s/n", dict) + + return nil +} + +// BindNameTrees syncs up the internal name tree cache with the xreftable. +func (xRefTable *XRefTable) BindNameTrees() error { + + log.Write.Println("BindNameTrees..") + + // Iterate over internal name tree rep. + for k, v := range xRefTable.Names { + log.Write.Printf("bindNameTree: %s\n", k) + if err := xRefTable.bindNameTreeNode(k, v, true); err != nil { + return err + } + } + + return nil +} + +// LocateNameTree locates/ensures a specific name tree. +func (xRefTable *XRefTable) LocateNameTree(nameTreeName string, ensure bool) error { + + if xRefTable.Names[nameTreeName] != nil { + return nil + } + + d, err := xRefTable.Catalog() + if err != nil { + return err + } + + o, found := d.Find("Names") + if !found { + if !ensure { + return nil + } + dict := NewDict() + + ir, err := xRefTable.IndRefForNewObject(dict) + if err != nil { + return err + } + d.Insert("Names", *ir) + + d = dict + } else { + d, err = xRefTable.DereferenceDict(o) + if err != nil { + return err + } + } + + o, found = d.Find(nameTreeName) + if !found { + if !ensure { + return nil + } + dict := NewDict() + dict.Insert("Names", Array{}) + + ir, err := xRefTable.IndRefForNewObject(dict) + if err != nil { + return err + } + + d.Insert(nameTreeName, *ir) + + xRefTable.Names[nameTreeName] = &Node{D: dict} + + return nil + } + + d1, err := xRefTable.DereferenceDict(o) + if err != nil { + return err + } + + xRefTable.Names[nameTreeName] = &Node{D: d1} + + return nil +} + +// NamesDict returns the dict that contains all name trees. +func (xRefTable *XRefTable) NamesDict() (Dict, error) { + + rootDict, err := xRefTable.Catalog() + if err != nil { + return nil, err + } + + o, found := rootDict.Find("Names") + if !found { + return nil, errors.New("pdfcpu: NamesDict: root entry \"Names\" missing") + } + + return xRefTable.DereferenceDict(o) +} + +// RemoveNameTree removes a specific name tree. +// Also removes a resulting empty names dict. +func (xRefTable *XRefTable) RemoveNameTree(nameTreeName string) error { + + namesDict, err := xRefTable.NamesDict() + if err != nil { + return err + } + + if namesDict == nil { + return errors.New("pdfcpu: removeNameTree: root entry \"Names\" corrupt") + } + + // We have an existing name dict. + + // Delete the name tree. + if err = xRefTable.deleteDictEntry(namesDict, nameTreeName); err != nil { + return err + } + if namesDict.Len() > 0 { + return nil + } + + // Remove empty names dict. + rootDict, err := xRefTable.Catalog() + if err != nil { + return err + } + if err = xRefTable.deleteDictEntry(rootDict, "Names"); err != nil { + return err + } + + log.Debug.Printf("Deleted Names from root: %s\n", rootDict) + + return nil +} + +// RemoveCollection removes an existing Collection entry from the catalog. +func (xRefTable *XRefTable) RemoveCollection() error { + rootDict, err := xRefTable.Catalog() + if err != nil { + return err + } + return xRefTable.deleteDictEntry(rootDict, "Collection") +} + +// EnsureCollection makes sure there is a Collection entry in the catalog. +// Needed for portfolio / portable collections eg. for file attachments. +func (xRefTable *XRefTable) EnsureCollection() error { + + rootDict, err := xRefTable.Catalog() + if err != nil { + return err + } + + _, found := rootDict.Find("Collection") + if found { + return nil + } + + dict := NewDict() + dict.Insert("Type", Name("Collection")) + dict.Insert("View", Name("D")) + + schemaDict := NewDict() + schemaDict.Insert("Type", Name("CollectionSchema")) + + fileNameCFDict := NewDict() + fileNameCFDict.Insert("Type", Name("CollectionField")) + fileNameCFDict.Insert("Subtype", Name("F")) + fileNameCFDict.Insert("N", StringLiteral("Filename")) + fileNameCFDict.Insert("O", Integer(1)) + schemaDict.Insert("FileName", fileNameCFDict) + + descCFDict := NewDict() + descCFDict.Insert("Type", Name("CollectionField")) + descCFDict.Insert("Subtype", Name("Desc")) + descCFDict.Insert("N", StringLiteral("Description")) + descCFDict.Insert("O", Integer(2)) + schemaDict.Insert("Description", descCFDict) + + sizeCFDict := NewDict() + sizeCFDict.Insert("Type", Name("CollectionField")) + sizeCFDict.Insert("Subtype", Name("Size")) + sizeCFDict.Insert("N", StringLiteral("Size")) + sizeCFDict.Insert("O", Integer(3)) + schemaDict.Insert("Size", sizeCFDict) + + modDateCFDict := NewDict() + modDateCFDict.Insert("Type", Name("CollectionField")) + modDateCFDict.Insert("Subtype", Name("ModDate")) + modDateCFDict.Insert("N", StringLiteral("Last Modification")) + modDateCFDict.Insert("O", Integer(4)) + schemaDict.Insert("ModDate", modDateCFDict) + + //TODO use xRefTable.InsertAndUseRecycled(xRefTableEntry) + + ir, err := xRefTable.IndRefForNewObject(schemaDict) + if err != nil { + return err + } + dict.Insert("Schema", *ir) + + sortDict := NewDict() + sortDict.Insert("S", Name("ModDate")) + sortDict.Insert("A", Boolean(false)) + dict.Insert("Sort", sortDict) + + ir, err = xRefTable.IndRefForNewObject(dict) + if err != nil { + return err + } + rootDict.Insert("Collection", *ir) + + return nil +} + +// RemoveEmbeddedFilesNameTree removes both the embedded files name tree and the Collection dict. +func (xRefTable *XRefTable) RemoveEmbeddedFilesNameTree() error { + + delete(xRefTable.Names, "EmbeddedFiles") + + if err := xRefTable.RemoveNameTree("EmbeddedFiles"); err != nil { + return err + } + + return xRefTable.RemoveCollection() +} + +// IDFirstElement returns the first element of ID. +func (xRefTable *XRefTable) IDFirstElement() (id []byte, err error) { + + hl, ok := xRefTable.ID[0].(HexLiteral) + if ok { + return hl.Bytes() + } + + sl, ok := xRefTable.ID[0].(StringLiteral) + if !ok { + return nil, errors.New("pdfcpu: ID must contain hex literals or string literals") + } + + return Unescape(sl.Value()) +} + +// InheritedPageAttrs represents all inherited page attributes. +type InheritedPageAttrs struct { + resources Dict // The closest resource dict to be inherited from parent nodes. + mediaBox *Rectangle + cropBox *Rectangle + rotate int +} + +func rect(xRefTable *XRefTable, a Array) (*Rectangle, error) { + + llx, err := xRefTable.DereferenceNumber(a[0]) + if err != nil { + return nil, err + } + + lly, err := xRefTable.DereferenceNumber(a[1]) + if err != nil { + return nil, err + } + + urx, err := xRefTable.DereferenceNumber(a[2]) + if err != nil { + return nil, err + } + + ury, err := xRefTable.DereferenceNumber(a[3]) + if err != nil { + return nil, err + } + + return Rect(llx, lly, urx, ury), nil +} + +func weaveResourceSubDict(d1, d2 Dict) { + for k, v := range d1 { + if v != nil { + v = v.Clone() + } + d2[k] = v + } +} + +func (xRefTable *XRefTable) consolidateResources(obj Object, pAttrs *InheritedPageAttrs) error { + d, err := xRefTable.DereferenceDict(obj) + if err != nil { + return err + } + if d == nil || len(d) == 0 { + return nil + } + + if pAttrs.resources == nil { + // Create a resource dict that eventually will contain any inherited resources + // while walking down from the page root to the leave node representing the page in question. + pAttrs.resources = d.Clone().(Dict) + for k, v := range pAttrs.resources { + o, err := xRefTable.Dereference(v) + if err != nil { + return err + } + pAttrs.resources[k] = o.Clone() + } + log.Write.Printf("pA:\n%s\n", pAttrs.resources) + return nil + } + + // Accumulate any resources defined in this page node into the inherited resources. + for k, v := range d { + if k == "ProcSet" || v == nil { + continue + } + d1, err := xRefTable.DereferenceDict(v) + if err != nil { + return err + } + if d1 == nil { + continue + } + // We have identified a subdict that needs to go into the inherited res dict. + if pAttrs.resources[k] == nil { + pAttrs.resources[k] = d1.Clone() + continue + } + d2, ok := pAttrs.resources[k].(Dict) + if !ok { + return errors.Errorf("pdfcpu: checkInheritedPageAttrs: expected Dict d2: %T", pAttrs.resources[k]) + } + // Weave sub dict d1 into inherited sub dict d2. + // Any existing resource names will be overridden. + weaveResourceSubDict(d1, d2) + } + + return nil +} + +func (xRefTable *XRefTable) checkInheritedPageAttrs(pageDict Dict, pAttrs *InheritedPageAttrs, consolidateRes bool) error { + // Compose a direct resource dict. + // if consolidateRes is true consolidate all inherited resources into it. + var ( + obj Object + found bool + ) + + if obj, found = pageDict.Find("MediaBox"); found { + a, err := xRefTable.DereferenceArray(obj) + if err != nil { + return err + } + if pAttrs.mediaBox, err = rect(xRefTable, a); err != nil { + return err + } + } + + if obj, found = pageDict.Find("CropBox"); found { + a, err := xRefTable.DereferenceArray(obj) + if err != nil { + return err + } + if pAttrs.cropBox, err = rect(xRefTable, a); err != nil { + return err + } + } + + if obj, found = pageDict.Find("Rotate"); found { + i, err := xRefTable.DereferenceInteger(obj) + if err != nil { + return err + } + pAttrs.rotate = i.Value() + } + + if !consolidateRes { + obj, found := pageDict.Find("Resources") + if found { + var err error + if pAttrs.resources, err = xRefTable.DereferenceDict(obj); err != nil { + return err + } + } + return nil + } + + // Accumulate all inherited resources. + if obj, found = pageDict.Find("Resources"); !found { + return nil + } + + return xRefTable.consolidateResources(obj, pAttrs) +} + +func consolidateResourceSubDict(d Dict, key string, prn PageResourceNames, pageNr int) error { + o := d[key] + if o == nil { + if prn.HasResources(key) { + return errors.Errorf("pdfcpu: page %d: missing required resource subdict: %s\n%s", pageNr, key, prn) + } + return nil + } + if !prn.HasResources(key) { + d.Delete(key) + return nil + } + d1 := o.(Dict) + set := StringSet{} + res := prn.Resources(key) + // Iterate over inherited resource sub dict and remove any entries not required. + for k := range d1 { + ki := Name(k).Value() + if !res[ki] { + d1.Delete(k) + continue + } + set[ki] = true + } + // Check for missing resource sub dict entries. + for k := range res { + if !set[k] { + return errors.Errorf("pdfcpu: page %d: missing required %s: %s", pageNr, key, k) + } + } + d[key] = d1 + return nil +} + +func consolidateResourceDict(d Dict, prn PageResourceNames, pageNr int) error { + for k := range resourceTypes { + if err := consolidateResourceSubDict(d, k, prn, pageNr); err != nil { + return err + } + } + return nil +} + +func consolidateResources(consolidateRes bool, xRefTable *XRefTable, pageDict, resDict Dict, page int) error { + if !consolidateRes { + return nil + } + + bb, err := xRefTable.PageContent(pageDict) + if err != nil { + if err == errNoContent { + return nil + } + return err + } + + // Calculate resources required by the content stream of this page. + prn, err := parseContent(string(bb)) + if err != nil { + return err + } + + // Compare required resouces (prn) with available resources (pAttrs.resources). + // Remove any resource that's not required. + // Return an error for any required resource missing. + // TODO Calculate and acumulate resources required by content streams of any present form or type 3 fonts. + return consolidateResourceDict(resDict, prn, page) +} + +func (xRefTable *XRefTable) processPageTreeForPageDict(root *IndirectRef, pAttrs *InheritedPageAttrs, p *int, page int, consolidateRes bool) (Dict, error) { + // Walk this page tree all the way down to the leave node representing page. + + //fmt.Printf("entering processPageTreeForPageDict: p=%d obj#%d\n", *p, root.ObjectNumber.Value()) + + d, err := xRefTable.DereferenceDict(*root) + if err != nil { + return nil, err + } + + pageCount := d.IntEntry("Count") + if pageCount != nil { + if *p+*pageCount < page { + // Skip sub pagetree. + *p += *pageCount + return nil, nil + } + } + + // Return the current state of all page attributes that may be inherited. + if err = xRefTable.checkInheritedPageAttrs(d, pAttrs, consolidateRes); err != nil { + return nil, err + } + + // Iterate over page tree. + kids := d.ArrayEntry("Kids") + if kids == nil { + return d, consolidateResources(consolidateRes, xRefTable, d, pAttrs.resources, page) + } + + for _, o := range kids { + + if o == nil { + continue + } + + // Dereference next page node dict. + ir, ok := o.(IndirectRef) + if !ok { + return nil, errors.Errorf("pdfcpu: processPageTreeForPageDict: corrupt page node dict") + } + + pageNodeDict, err := xRefTable.DereferenceDict(ir) + if err != nil { + return nil, err + } + + switch *pageNodeDict.Type() { + + case "Pages": + // Recurse over sub pagetree. + pageNodeDict, err = xRefTable.processPageTreeForPageDict(&ir, pAttrs, p, page, consolidateRes) + if err != nil { + return nil, err + } + if pageNodeDict != nil { + return pageNodeDict, nil + } + + case "Page": + *p++ + if *p == page { + return xRefTable.processPageTreeForPageDict(&ir, pAttrs, p, page, consolidateRes) + } + + } + + } + + return nil, nil +} + +// PageDict returns a specific page dict along with the resources, mediaBox and CropBox in effect. +func (xRefTable *XRefTable) PageDict(page int, consolidateRes bool) (Dict, *InheritedPageAttrs, error) { + + // Get an indirect reference to the page tree root dict. + pageRootDictIndRef, _ := xRefTable.Pages() + + var ( + inhPAttrs InheritedPageAttrs + pageCount int + ) + + // Calculate and return only resources that are really needed by + // any content stream of this page and any possible forms or type 3 fonts referenced. + pageDict, err := xRefTable.processPageTreeForPageDict(pageRootDictIndRef, &inhPAttrs, &pageCount, page, consolidateRes) + if err != nil { + return nil, nil, err + } + + return pageDict, &inhPAttrs, nil +} + +func (xRefTable *XRefTable) processPageTreeForPageNumber(root *IndirectRef, pageCount *int, pageObjNr int) (int, error) { + + //fmt.Printf("entering processPageTreeForPageNumber: p=%d obj#%d\n", *p, root.ObjectNumber.Value()) + + d, err := xRefTable.DereferenceDict(*root) + if err != nil { + return 0, err + } + + // Iterate over page tree. + for _, o := range d.ArrayEntry("Kids") { + + if o == nil { + continue + } + + // Dereference next page node dict. + ir, ok := o.(IndirectRef) + if !ok { + return 0, errors.Errorf("pdfcpu: processPageTreeForPageNumber: corrupt page node dict") + } + + objNr := ir.ObjectNumber.Value() + + pageNodeDict, err := xRefTable.DereferenceDict(ir) + if err != nil { + return 0, err + } + + switch *pageNodeDict.Type() { + + case "Pages": + // Recurse over sub pagetree. + pageNr, err := xRefTable.processPageTreeForPageNumber(&ir, pageCount, pageObjNr) + if err != nil { + return 0, err + } + if pageNr > 0 { + return pageNr, nil + } + + case "Page": + *pageCount++ + if objNr == pageObjNr { + return *pageCount, nil + } + } + + } + + return 0, nil +} + +// PageNumber returns the logical page number for a page dict object number. +func (xRefTable *XRefTable) PageNumber(pageObjNr int) (int, error) { + // Get an indirect reference to the page tree root dict. + pageRootDict, _ := xRefTable.Pages() + pageCount := 0 + return xRefTable.processPageTreeForPageNumber(pageRootDict, &pageCount, pageObjNr) +} + +// EnsurePageCount evaluates the page count for xRefTable if necessary. +// Important when validation is turned off. +func (xRefTable *XRefTable) EnsurePageCount() error { + + if xRefTable.PageCount > 0 { + return nil + } + + pageRoot, err := xRefTable.Pages() + if err != nil { + return err + } + + d, err := xRefTable.DereferenceDict(*pageRoot) + if err != nil { + return err + } + + pageCount := d.IntEntry("Count") + if pageCount == nil { + return errors.New("pdfcpu: pageDict: missing \"Count\"") + } + + xRefTable.PageCount = *pageCount + + return nil +} + +func (xRefTable *XRefTable) resolvePageBoundary(d Dict, boxName string) (*Rectangle, error) { + obj, found := d.Find(boxName) + if !found { + return nil, nil + } + a, err := xRefTable.DereferenceArray(obj) + if err != nil { + return nil, err + } + return rect(xRefTable, a) +} + +func (xRefTable *XRefTable) collectPageBoundariesForPage(d Dict, pb []PageBoundaries, inhMediaBox, inhCropBox *Rectangle, p int) error { + if inhMediaBox != nil { + pb[p].Media = &Box{Rect: inhMediaBox, Inherited: true} + } + r, err := xRefTable.resolvePageBoundary(d, "MediaBox") + if err != nil { + return err + } + if r != nil { + pb[p].Media = &Box{Rect: r, Inherited: false} + } + if pb[p].Media == nil { + return errors.New("pdfcpu: collectMediaBoxesForPageTree: mediaBox is nil") + } + + if inhCropBox != nil && inhCropBox.Rectangle != nil { + pb[p].Crop = &Box{Rect: inhCropBox, Inherited: true} + } + r, err = xRefTable.resolvePageBoundary(d, "CropBox") + if err != nil { + return err + } + if r != nil { + pb[p].Crop = &Box{Rect: r, Inherited: false} + } + + r, err = xRefTable.resolvePageBoundary(d, "TrimBox") + if err != nil { + return err + } + if r != nil { + pb[p].Trim = &Box{Rect: r} + } + + r, err = xRefTable.resolvePageBoundary(d, "BleedBox") + if err != nil { + return err + } + if r != nil { + pb[p].Bleed = &Box{Rect: r} + } + + r, err = xRefTable.resolvePageBoundary(d, "ArtBox") + if err != nil { + return err + } + if r != nil { + pb[p].Art = &Box{Rect: r} + } + + return nil +} + +func (xRefTable *XRefTable) collectMediaBoxAndCropBox(d Dict, inhMediaBox, inhCropBox **Rectangle) error { + obj, found := d.Find("MediaBox") + if found { + a, err := xRefTable.DereferenceArray(obj) + if err != nil { + return err + } + if *inhMediaBox, err = rect(xRefTable, a); err != nil { + return err + } + *inhCropBox = nil + //if kids == nil { + // pb[*p].Media = &Box{Rect: *inhMediaBox} + //} + } + + obj, found = d.Find("CropBox") + if found { + a, err := xRefTable.DereferenceArray(obj) + if err != nil { + return err + } + if *inhCropBox, err = rect(xRefTable, a); err != nil { + return err + } + } + return nil +} + +func (xRefTable *XRefTable) collectPageBoundariesForPageTree(root *IndirectRef, inhMediaBox, inhCropBox **Rectangle, pb []PageBoundaries, p *int) error { + d, err := xRefTable.DereferenceDict(*root) + if err != nil { + return err + } + + kids := d.ArrayEntry("Kids") + if kids == nil { + return xRefTable.collectPageBoundariesForPage(d, pb, *inhMediaBox, *inhCropBox, *p) + } + + if err := xRefTable.collectMediaBoxAndCropBox(d, inhMediaBox, inhCropBox); err != nil { + return err + } + + // Iterate over page tree. + for _, o := range kids { + + if o == nil { + continue + } + + // Dereference next page node dict. + ir, ok := o.(IndirectRef) + if !ok { + return errors.Errorf("pdfcpu: collectMediaBoxesForPageTree: corrupt page node dict") + } + + pageNodeDict, err := xRefTable.DereferenceDict(ir) + if err != nil { + return err + } + + switch *pageNodeDict.Type() { + + case "Pages": + if err = xRefTable.collectPageBoundariesForPageTree(&ir, inhMediaBox, inhCropBox, pb, p); err != nil { + return err + } + + case "Page": + if err = xRefTable.collectPageBoundariesForPageTree(&ir, inhMediaBox, inhCropBox, pb, p); err != nil { + return err + } + *p++ + } + + } + + return nil +} + +// PageBoundaries returns a sorted slice with page boundaries +// for all pages sorted ascending by page number. +func (xRefTable *XRefTable) PageBoundaries() ([]PageBoundaries, error) { + if err := xRefTable.EnsurePageCount(); err != nil { + return nil, err + } + + // Get an indirect reference to the page tree root dict. + root, err := xRefTable.Pages() + if err != nil { + return nil, err + } + + i := 0 + mb := &Rectangle{} + cb := &Rectangle{} + pbs := make([]PageBoundaries, xRefTable.PageCount) + if err := xRefTable.collectPageBoundariesForPageTree(root, &mb, &cb, pbs, &i); err != nil { + return nil, err + } + return pbs, nil +} + +// PageDims returns a sorted slice with media box dimensions +// for all pages sorted ascending by page number. +func (xRefTable *XRefTable) PageDims() ([]Dim, error) { + pbs, err := xRefTable.PageBoundaries() + if err != nil { + return nil, err + } + + dims := make([]Dim, len(pbs)) + for i, pb := range pbs { + dims[i] = pb.MediaBox().Dimensions() + } + + return dims, nil +} + +func (xRefTable *XRefTable) emptyPage(parentIndRef *IndirectRef, mediaBox *Rectangle) (*IndirectRef, error) { + sd, _ := xRefTable.NewStreamDictForBuf(nil) + + if err := sd.Encode(); err != nil { + return nil, err + } + + contentsIndRef, err := xRefTable.IndRefForNewObject(*sd) + if err != nil { + return nil, err + } + + pageDict := Dict( + map[string]Object{ + "Type": Name("Page"), + "Parent": *parentIndRef, + "Resources": NewDict(), + "MediaBox": mediaBox.Array(), + "Contents": *contentsIndRef, + }, + ) + + return xRefTable.IndRefForNewObject(pageDict) +} + +func (xRefTable *XRefTable) pageMediaBox(d *Dict) (*Rectangle, error) { + + o, found := d.Find("MediaBox") + if !found { + return nil, errors.Errorf("pdfcpu: pageMediaBox: missing mediaBox") + } + + a, err := xRefTable.DereferenceArray(o) + if err != nil { + return nil, err + } + + return rect(xRefTable, a) +} + +func (xRefTable *XRefTable) insertEmptyPage(root *IndirectRef, pAttrs *InheritedPageAttrs, pageNodeDict Dict) (indRef *IndirectRef, err error) { + mediaBox := pAttrs.mediaBox + if mediaBox == nil { + mediaBox, err = xRefTable.pageMediaBox(&pageNodeDict) + if err != nil { + return nil, err + } + } + + return xRefTable.emptyPage(root, mediaBox) +} + +func (xRefTable *XRefTable) insertBlankPagesIntoPageTree(root *IndirectRef, pAttrs *InheritedPageAttrs, p *int, selectedPages IntSet, before bool) (int, error) { + + d, err := xRefTable.DereferenceDict(*root) + if err != nil { + return 0, err + } + + consolidateRes := false + err = xRefTable.checkInheritedPageAttrs(d, pAttrs, consolidateRes) + if err != nil { + return 0, err + } + + kids := d.ArrayEntry("Kids") + if kids == nil { + return 0, nil + } + + i := 0 + a := Array{} + + for _, o := range kids { + + if o == nil { + continue + } + + // Dereference next page node dict. + ir, ok := o.(IndirectRef) + if !ok { + return 0, errors.Errorf("pdfcpu: insertIntoPageTree: corrupt page node dict") + } + + pageNodeDict, err := xRefTable.DereferenceDict(ir) + if err != nil { + return 0, err + } + + switch *pageNodeDict.Type() { + + case "Pages": + // Recurse over sub pagetree. + j, err := xRefTable.insertBlankPagesIntoPageTree(&ir, pAttrs, p, selectedPages, before) + if err != nil { + return 0, err + } + a = append(a, ir) + i += j + + case "Page": + *p++ + if !before { + a = append(a, ir) + i++ + } + if selectedPages[*p] { + // Insert empty page. + indRef, err := xRefTable.insertEmptyPage(root, pAttrs, pageNodeDict) + if err != nil { + return 0, err + } + + a = append(a, *indRef) + i++ + } + if before { + a = append(a, ir) + i++ + } + + } + + } + + d.Update("Kids", a) + + return i, d.IncrementBy("Count", i) +} + +// InsertBlankPages inserts a blank page before or after each selected page. +func (xRefTable *XRefTable) InsertBlankPages(pages IntSet, before bool) error { + + root, err := xRefTable.Pages() + if err != nil { + return err + } + + var inhPAttrs InheritedPageAttrs + p := 0 + + _, err = xRefTable.insertBlankPagesIntoPageTree(root, &inhPAttrs, &p, pages, before) + + return err +} diff --git a/vendor/github.com/pdfcpu/pdfcpu/pkg/types/types.go b/vendor/github.com/pdfcpu/pdfcpu/pkg/types/types.go new file mode 100644 index 0000000..b798f76 --- /dev/null +++ b/vendor/github.com/pdfcpu/pdfcpu/pkg/types/types.go @@ -0,0 +1,84 @@ +/* +Copyright 2018 The pdfcpu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package types provides pdfcpu's base types. +package types + +import "fmt" + +// Point represents a user space location. +type Point struct { + X, Y float64 +} + +// Translate modifies p's coordinates. +func (p *Point) Translate(dx, dy float64) { + p.X += dx + p.Y += dy +} + +func (p Point) String() string { + return fmt.Sprintf("(%.2f,%.2f)\n", p.X, p.Y) +} + +// Rectangle represents a rectangular region in userspace. +type Rectangle struct { + LL, UR Point +} + +// Width returns the horizontal span of a rectangle in userspace. +func (r Rectangle) Width() float64 { + return r.UR.X - r.LL.X +} + +// Height returns the vertical span of a rectangle in userspace. +func (r Rectangle) Height() float64 { + return r.UR.Y - r.LL.Y +} + +// AspectRatio returns the relation between width and height of a rectangle. +func (r Rectangle) AspectRatio() float64 { + return r.Width() / r.Height() +} + +// Landscape returns true if r is in landscape mode. +func (r Rectangle) Landscape() bool { + return r.AspectRatio() > 1 +} + +// Portrait returns true if r is in portrait mode. +func (r Rectangle) Portrait() bool { + return r.AspectRatio() < 1 +} + +// Center returns the center point of a rectangle. +func (r Rectangle) Center() Point { + return Point{(r.UR.X - r.Width()/2), (r.UR.Y - r.Height()/2)} +} + +// Contains returns true if rectangle r contains point p. +func (r Rectangle) Contains(p Point) bool { + return p.X >= r.LL.X && p.X <= r.UR.X && p.Y >= r.LL.Y && p.Y <= r.LL.Y +} + +func (r Rectangle) String() string { + return fmt.Sprintf("(%3.2f, %3.2f, %3.2f, %3.2f) w=%.2f h=%.2f ar=%.2f", r.LL.X, r.LL.Y, r.UR.X, r.UR.Y, r.Width(), r.Height(), r.AspectRatio()) +} + +// NewRectangle returns a new rectangle for given corner coordinates. +func NewRectangle(llx, lly, urx, ury float64) *Rectangle { + return &Rectangle{LL: Point{llx, lly}, UR: Point{urx, ury}} +} diff --git a/vendor/golang.org/x/image/AUTHORS b/vendor/golang.org/x/image/AUTHORS new file mode 100644 index 0000000..15167cd --- /dev/null +++ b/vendor/golang.org/x/image/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/image/CONTRIBUTORS b/vendor/golang.org/x/image/CONTRIBUTORS new file mode 100644 index 0000000..1c4577e --- /dev/null +++ b/vendor/golang.org/x/image/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/image/LICENSE b/vendor/golang.org/x/image/LICENSE new file mode 100644 index 0000000..6a66aea --- /dev/null +++ b/vendor/golang.org/x/image/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/image/PATENTS b/vendor/golang.org/x/image/PATENTS new file mode 100644 index 0000000..7330990 --- /dev/null +++ b/vendor/golang.org/x/image/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/image/ccitt/reader.go b/vendor/golang.org/x/image/ccitt/reader.go new file mode 100644 index 0000000..340de05 --- /dev/null +++ b/vendor/golang.org/x/image/ccitt/reader.go @@ -0,0 +1,795 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run gen.go + +// Package ccitt implements a CCITT (fax) image decoder. +package ccitt + +import ( + "encoding/binary" + "errors" + "image" + "io" + "math/bits" +) + +var ( + errIncompleteCode = errors.New("ccitt: incomplete code") + errInvalidBounds = errors.New("ccitt: invalid bounds") + errInvalidCode = errors.New("ccitt: invalid code") + errInvalidMode = errors.New("ccitt: invalid mode") + errInvalidOffset = errors.New("ccitt: invalid offset") + errMissingEOL = errors.New("ccitt: missing End-of-Line") + errRunLengthOverflowsWidth = errors.New("ccitt: run length overflows width") + errRunLengthTooLong = errors.New("ccitt: run length too long") + errUnsupportedMode = errors.New("ccitt: unsupported mode") + errUnsupportedSubFormat = errors.New("ccitt: unsupported sub-format") + errUnsupportedWidth = errors.New("ccitt: unsupported width") +) + +// Order specifies the bit ordering in a CCITT data stream. +type Order uint32 + +const ( + // LSB means Least Significant Bits first. + LSB Order = iota + // MSB means Most Significant Bits first. + MSB +) + +// SubFormat represents that the CCITT format consists of a number of +// sub-formats. Decoding or encoding a CCITT data stream requires knowing the +// sub-format context. It is not represented in the data stream per se. +type SubFormat uint32 + +const ( + Group3 SubFormat = iota + Group4 +) + +// AutoDetectHeight is passed as the height argument to NewReader to indicate +// that the image height (the number of rows) is not known in advance. +const AutoDetectHeight = -1 + +// Options are optional parameters. +type Options struct { + // Align means that some variable-bit-width codes are byte-aligned. + Align bool + // Invert means that black is the 1 bit or 0xFF byte, and white is 0. + Invert bool +} + +// maxWidth is the maximum (inclusive) supported width. This is a limitation of +// this implementation, to guard against integer overflow, and not anything +// inherent to the CCITT format. +const maxWidth = 1 << 20 + +func invertBytes(b []byte) { + for i, c := range b { + b[i] = ^c + } +} + +func reverseBitsWithinBytes(b []byte) { + for i, c := range b { + b[i] = bits.Reverse8(c) + } +} + +// highBits writes to dst (1 bit per pixel, most significant bit first) the +// high (0x80) bits from src (1 byte per pixel). It returns the number of bytes +// written and read such that dst[:d] is the packed form of src[:s]. +// +// For example, if src starts with the 8 bytes [0x7D, 0x7E, 0x7F, 0x80, 0x81, +// 0x82, 0x00, 0xFF] then 0x1D will be written to dst[0]. +// +// If src has (8 * len(dst)) or more bytes then only len(dst) bytes are +// written, (8 * len(dst)) bytes are read, and invert is ignored. +// +// Otherwise, if len(src) is not a multiple of 8 then the final byte written to +// dst is padded with 1 bits (if invert is true) or 0 bits. If inverted, the 1s +// are typically temporary, e.g. they will be flipped back to 0s by an +// invertBytes call in the highBits caller, reader.Read. +func highBits(dst []byte, src []byte, invert bool) (d int, s int) { + // Pack as many complete groups of 8 src bytes as we can. + n := len(src) / 8 + if n > len(dst) { + n = len(dst) + } + dstN := dst[:n] + for i := range dstN { + src8 := src[i*8 : i*8+8] + dstN[i] = ((src8[0] & 0x80) >> 0) | + ((src8[1] & 0x80) >> 1) | + ((src8[2] & 0x80) >> 2) | + ((src8[3] & 0x80) >> 3) | + ((src8[4] & 0x80) >> 4) | + ((src8[5] & 0x80) >> 5) | + ((src8[6] & 0x80) >> 6) | + ((src8[7] & 0x80) >> 7) + } + d, s = n, 8*n + dst, src = dst[d:], src[s:] + + // Pack up to 7 remaining src bytes, if there's room in dst. + if (len(dst) > 0) && (len(src) > 0) { + dstByte := byte(0) + if invert { + dstByte = 0xFF >> uint(len(src)) + } + for n, srcByte := range src { + dstByte |= (srcByte & 0x80) >> uint(n) + } + dst[0] = dstByte + d, s = d+1, s+len(src) + } + return d, s +} + +type bitReader struct { + r io.Reader + + // readErr is the error returned from the most recent r.Read call. As the + // io.Reader documentation says, when r.Read returns (n, err), "always + // process the n > 0 bytes returned before considering the error err". + readErr error + + // order is whether to process r's bytes LSB first or MSB first. + order Order + + // The high nBits bits of the bits field hold upcoming bits in MSB order. + bits uint64 + nBits uint32 + + // bytes[br:bw] holds bytes read from r but not yet loaded into bits. + br uint32 + bw uint32 + bytes [1024]uint8 +} + +func (b *bitReader) alignToByteBoundary() { + n := b.nBits & 7 + b.bits <<= n + b.nBits -= n +} + +// nextBitMaxNBits is the maximum possible value of bitReader.nBits after a +// bitReader.nextBit call, provided that bitReader.nBits was not more than this +// value before that call. +// +// Note that the decode function can unread bits, which can temporarily set the +// bitReader.nBits value above nextBitMaxNBits. +const nextBitMaxNBits = 31 + +func (b *bitReader) nextBit() (uint64, error) { + for { + if b.nBits > 0 { + bit := b.bits >> 63 + b.bits <<= 1 + b.nBits-- + return bit, nil + } + + if available := b.bw - b.br; available >= 4 { + // Read 32 bits, even though b.bits is a uint64, since the decode + // function may need to unread up to maxCodeLength bits, putting + // them back in the remaining (64 - 32) bits. TestMaxCodeLength + // checks that the generated maxCodeLength constant fits. + // + // If changing the Uint32 call, also change nextBitMaxNBits. + b.bits = uint64(binary.BigEndian.Uint32(b.bytes[b.br:])) << 32 + b.br += 4 + b.nBits = 32 + continue + } else if available > 0 { + b.bits = uint64(b.bytes[b.br]) << (7 * 8) + b.br++ + b.nBits = 8 + continue + } + + if b.readErr != nil { + return 0, b.readErr + } + + n, err := b.r.Read(b.bytes[:]) + b.br = 0 + b.bw = uint32(n) + b.readErr = err + + if b.order != MSB { + reverseBitsWithinBytes(b.bytes[:b.bw]) + } + } +} + +func decode(b *bitReader, decodeTable [][2]int16) (uint32, error) { + nBitsRead, bitsRead, state := uint32(0), uint64(0), int32(1) + for { + bit, err := b.nextBit() + if err != nil { + if err == io.EOF { + err = errIncompleteCode + } + return 0, err + } + bitsRead |= bit << (63 - nBitsRead) + nBitsRead++ + + // The "&1" is redundant, but can eliminate a bounds check. + state = int32(decodeTable[state][bit&1]) + if state < 0 { + return uint32(^state), nil + } else if state == 0 { + // Unread the bits we've read, then return errInvalidCode. + b.bits = (b.bits >> nBitsRead) | bitsRead + b.nBits += nBitsRead + return 0, errInvalidCode + } + } +} + +// decodeEOL decodes the 12-bit EOL code 0000_0000_0001. +func decodeEOL(b *bitReader) error { + nBitsRead, bitsRead := uint32(0), uint64(0) + for { + bit, err := b.nextBit() + if err != nil { + if err == io.EOF { + err = errMissingEOL + } + return err + } + bitsRead |= bit << (63 - nBitsRead) + nBitsRead++ + + if nBitsRead < 12 { + if bit&1 == 0 { + continue + } + } else if bit&1 != 0 { + return nil + } + + // Unread the bits we've read, then return errMissingEOL. + b.bits = (b.bits >> nBitsRead) | bitsRead + b.nBits += nBitsRead + return errMissingEOL + } +} + +type reader struct { + br bitReader + subFormat SubFormat + + // width is the image width in pixels. + width int + + // rowsRemaining starts at the image height in pixels, when the reader is + // driven through the io.Reader interface, and decrements to zero as rows + // are decoded. Alternatively, it may be negative if the image height is + // not known in advance at the time of the NewReader call. + // + // When driven through DecodeIntoGray, this field is unused. + rowsRemaining int + + // curr and prev hold the current and previous rows. Each element is either + // 0x00 (black) or 0xFF (white). + // + // prev may be nil, when processing the first row. + curr []byte + prev []byte + + // ri is the read index. curr[:ri] are those bytes of curr that have been + // passed along via the Read method. + // + // When the reader is driven through DecodeIntoGray, instead of through the + // io.Reader interface, this field is unused. + ri int + + // wi is the write index. curr[:wi] are those bytes of curr that have + // already been decoded via the decodeRow method. + // + // What this implementation calls wi is roughly equivalent to what the spec + // calls the a0 index. + wi int + + // These fields are copied from the *Options (which may be nil). + align bool + invert bool + + // atStartOfRow is whether we have just started the row. Some parts of the + // spec say to treat this situation as if "wi = -1". + atStartOfRow bool + + // penColorIsWhite is whether the next run is black or white. + penColorIsWhite bool + + // seenStartOfImage is whether we've called the startDecode method. + seenStartOfImage bool + + // truncated is whether the input is missing the final 6 consecutive EOL's + // (for Group3) or 2 consecutive EOL's (for Group4). Omitting that trailer + // (but otherwise padding to a byte boundary, with either all 0 bits or all + // 1 bits) is invalid according to the spec, but happens in practice when + // exporting from Adobe Acrobat to TIFF + CCITT. This package silently + // ignores the format error for CCITT input that has been truncated in that + // fashion, returning the full decoded image. + // + // Detecting trailer truncation (just after the final row of pixels) + // requires knowing which row is the final row, and therefore does not + // trigger if the image height is not known in advance. + truncated bool + + // readErr is a sticky error for the Read method. + readErr error +} + +func (z *reader) Read(p []byte) (int, error) { + if z.readErr != nil { + return 0, z.readErr + } + originalP := p + + for len(p) > 0 { + // Allocate buffers (and decode any start-of-image codes), if + // processing the first or second row. + if z.curr == nil { + if !z.seenStartOfImage { + if z.readErr = z.startDecode(); z.readErr != nil { + break + } + z.atStartOfRow = true + } + z.curr = make([]byte, z.width) + } + + // Decode the next row, if necessary. + if z.atStartOfRow { + if z.rowsRemaining < 0 { + // We do not know the image height in advance. See if the next + // code is an EOL. If it is, it is consumed. If it isn't, the + // bitReader shouldn't advance along the bit stream, and we + // simply decode another row of pixel data. + // + // For the Group4 subFormat, we may need to align to a byte + // boundary. For the Group3 subFormat, the previous z.decodeRow + // call (or z.startDecode call) has already consumed one of the + // 6 consecutive EOL's. The next EOL is actually the second of + // 6, in the middle, and we shouldn't align at that point. + if z.align && (z.subFormat == Group4) { + z.br.alignToByteBoundary() + } + + if err := z.decodeEOL(); err == errMissingEOL { + // No-op. It's another row of pixel data. + } else if err != nil { + z.readErr = err + break + } else { + if z.readErr = z.finishDecode(true); z.readErr != nil { + break + } + z.readErr = io.EOF + break + } + + } else if z.rowsRemaining == 0 { + // We do know the image height in advance, and we have already + // decoded exactly that many rows. + if z.readErr = z.finishDecode(false); z.readErr != nil { + break + } + z.readErr = io.EOF + break + + } else { + z.rowsRemaining-- + } + + if z.readErr = z.decodeRow(z.rowsRemaining == 0); z.readErr != nil { + break + } + } + + // Pack from z.curr (1 byte per pixel) to p (1 bit per pixel). + packD, packS := highBits(p, z.curr[z.ri:], z.invert) + p = p[packD:] + z.ri += packS + + // Prepare to decode the next row, if necessary. + if z.ri == len(z.curr) { + z.ri, z.curr, z.prev = 0, z.prev, z.curr + z.atStartOfRow = true + } + } + + n := len(originalP) - len(p) + if z.invert { + invertBytes(originalP[:n]) + } + return n, z.readErr +} + +func (z *reader) penColor() byte { + if z.penColorIsWhite { + return 0xFF + } + return 0x00 +} + +func (z *reader) startDecode() error { + switch z.subFormat { + case Group3: + if err := z.decodeEOL(); err != nil { + return err + } + + case Group4: + // No-op. + + default: + return errUnsupportedSubFormat + } + + z.seenStartOfImage = true + return nil +} + +func (z *reader) finishDecode(alreadySeenEOL bool) error { + numberOfEOLs := 0 + switch z.subFormat { + case Group3: + if z.truncated { + return nil + } + // The stream ends with a RTC (Return To Control) of 6 consecutive + // EOL's, but we should have already just seen an EOL, either in + // z.startDecode (for a zero-height image) or in z.decodeRow. + numberOfEOLs = 5 + + case Group4: + autoDetectHeight := z.rowsRemaining < 0 + if autoDetectHeight { + // Aligning to a byte boundary was already handled by reader.Read. + } else if z.align { + z.br.alignToByteBoundary() + } + // The stream ends with two EOL's. If the first one is missing, and we + // had an explicit image height, we just assume that the trailing two + // EOL's were truncated and return a nil error. + if err := z.decodeEOL(); err != nil { + if (err == errMissingEOL) && !autoDetectHeight { + z.truncated = true + return nil + } + return err + } + numberOfEOLs = 1 + + default: + return errUnsupportedSubFormat + } + + if alreadySeenEOL { + numberOfEOLs-- + } + for ; numberOfEOLs > 0; numberOfEOLs-- { + if err := z.decodeEOL(); err != nil { + return err + } + } + return nil +} + +func (z *reader) decodeEOL() error { + return decodeEOL(&z.br) +} + +func (z *reader) decodeRow(finalRow bool) error { + z.wi = 0 + z.atStartOfRow = true + z.penColorIsWhite = true + + if z.align { + z.br.alignToByteBoundary() + } + + switch z.subFormat { + case Group3: + for ; z.wi < len(z.curr); z.atStartOfRow = false { + if err := z.decodeRun(); err != nil { + return err + } + } + err := z.decodeEOL() + if finalRow && (err == errMissingEOL) { + z.truncated = true + return nil + } + return err + + case Group4: + for ; z.wi < len(z.curr); z.atStartOfRow = false { + mode, err := decode(&z.br, modeDecodeTable[:]) + if err != nil { + return err + } + rm := readerMode{} + if mode < uint32(len(readerModes)) { + rm = readerModes[mode] + } + if rm.function == nil { + return errInvalidMode + } + if err := rm.function(z, rm.arg); err != nil { + return err + } + } + return nil + } + + return errUnsupportedSubFormat +} + +func (z *reader) decodeRun() error { + table := blackDecodeTable[:] + if z.penColorIsWhite { + table = whiteDecodeTable[:] + } + + total := 0 + for { + n, err := decode(&z.br, table) + if err != nil { + return err + } + if n > maxWidth { + panic("unreachable") + } + total += int(n) + if total > maxWidth { + return errRunLengthTooLong + } + // Anything 0x3F or below is a terminal code. + if n <= 0x3F { + break + } + } + + if total > (len(z.curr) - z.wi) { + return errRunLengthOverflowsWidth + } + dst := z.curr[z.wi : z.wi+total] + penColor := z.penColor() + for i := range dst { + dst[i] = penColor + } + z.wi += total + z.penColorIsWhite = !z.penColorIsWhite + + return nil +} + +// The various modes' semantics are based on determining a row of pixels' +// "changing elements": those pixels whose color differs from the one on its +// immediate left. +// +// The row above the first row is implicitly all white. Similarly, the column +// to the left of the first column is implicitly all white. +// +// For example, here's Figure 1 in "ITU-T Recommendation T.6", where the +// current and previous rows contain black (B) and white (w) pixels. The a? +// indexes point into curr, the b? indexes point into prev. +// +// b1 b2 +// v v +// prev: BBBBBwwwwwBBBwwwww +// curr: BBBwwwwwBBBBBBwwww +// ^ ^ ^ +// a0 a1 a2 +// +// a0 is the "reference element" or current decoder position, roughly +// equivalent to what this implementation calls reader.wi. +// +// a1 is the next changing element to the right of a0, on the "coding line" +// (the current row). +// +// a2 is the next changing element to the right of a1, again on curr. +// +// b1 is the first changing element on the "reference line" (the previous row) +// to the right of a0 and of opposite color to a0. +// +// b2 is the next changing element to the right of b1, again on prev. +// +// The various modes calculate a1 (and a2, for modeH): +// - modePass calculates that a1 is at or to the right of b2. +// - modeH calculates a1 and a2 without considering b1 or b2. +// - modeV* calculates a1 to be b1 plus an adjustment (between -3 and +3). + +const ( + findB1 = false + findB2 = true +) + +// findB finds either the b1 or b2 value. +func (z *reader) findB(whichB bool) int { + // The initial row is a special case. The previous row is implicitly all + // white, so that there are no changing pixel elements. We return b1 or b2 + // to be at the end of the row. + if len(z.prev) != len(z.curr) { + return len(z.curr) + } + + i := z.wi + + if z.atStartOfRow { + // a0 is implicitly at -1, on a white pixel. b1 is the first black + // pixel in the previous row. b2 is the first white pixel after that. + for ; (i < len(z.prev)) && (z.prev[i] == 0xFF); i++ { + } + if whichB == findB2 { + for ; (i < len(z.prev)) && (z.prev[i] == 0x00); i++ { + } + } + return i + } + + // As per figure 1 above, assume that the current pen color is white. + // First, walk past every contiguous black pixel in prev, starting at a0. + oppositeColor := ^z.penColor() + for ; (i < len(z.prev)) && (z.prev[i] == oppositeColor); i++ { + } + + // Then walk past every contiguous white pixel. + penColor := ^oppositeColor + for ; (i < len(z.prev)) && (z.prev[i] == penColor); i++ { + } + + // We're now at a black pixel (or at the end of the row). That's b1. + if whichB == findB2 { + // If we're looking for b2, walk past every contiguous black pixel + // again. + oppositeColor := ^penColor + for ; (i < len(z.prev)) && (z.prev[i] == oppositeColor); i++ { + } + } + + return i +} + +type readerMode struct { + function func(z *reader, arg int) error + arg int +} + +var readerModes = [...]readerMode{ + modePass: {function: readerModePass}, + modeH: {function: readerModeH}, + modeV0: {function: readerModeV, arg: +0}, + modeVR1: {function: readerModeV, arg: +1}, + modeVR2: {function: readerModeV, arg: +2}, + modeVR3: {function: readerModeV, arg: +3}, + modeVL1: {function: readerModeV, arg: -1}, + modeVL2: {function: readerModeV, arg: -2}, + modeVL3: {function: readerModeV, arg: -3}, + modeExt: {function: readerModeExt}, +} + +func readerModePass(z *reader, arg int) error { + b2 := z.findB(findB2) + if (b2 < z.wi) || (len(z.curr) < b2) { + return errInvalidOffset + } + dst := z.curr[z.wi:b2] + penColor := z.penColor() + for i := range dst { + dst[i] = penColor + } + z.wi = b2 + return nil +} + +func readerModeH(z *reader, arg int) error { + // The first iteration finds a1. The second finds a2. + for i := 0; i < 2; i++ { + if err := z.decodeRun(); err != nil { + return err + } + } + return nil +} + +func readerModeV(z *reader, arg int) error { + a1 := z.findB(findB1) + arg + if (a1 < z.wi) || (len(z.curr) < a1) { + return errInvalidOffset + } + dst := z.curr[z.wi:a1] + penColor := z.penColor() + for i := range dst { + dst[i] = penColor + } + z.wi = a1 + z.penColorIsWhite = !z.penColorIsWhite + return nil +} + +func readerModeExt(z *reader, arg int) error { + return errUnsupportedMode +} + +// DecodeIntoGray decodes the CCITT-formatted data in r into dst. +// +// It returns an error if dst's width and height don't match the implied width +// and height of CCITT-formatted data. +func DecodeIntoGray(dst *image.Gray, r io.Reader, order Order, sf SubFormat, opts *Options) error { + bounds := dst.Bounds() + if (bounds.Dx() < 0) || (bounds.Dy() < 0) { + return errInvalidBounds + } + if bounds.Dx() > maxWidth { + return errUnsupportedWidth + } + + z := reader{ + br: bitReader{r: r, order: order}, + subFormat: sf, + align: (opts != nil) && opts.Align, + invert: (opts != nil) && opts.Invert, + width: bounds.Dx(), + } + if err := z.startDecode(); err != nil { + return err + } + + width := bounds.Dx() + for y := bounds.Min.Y; y < bounds.Max.Y; y++ { + p := (y - bounds.Min.Y) * dst.Stride + z.curr = dst.Pix[p : p+width] + if err := z.decodeRow(y+1 == bounds.Max.Y); err != nil { + return err + } + z.curr, z.prev = nil, z.curr + } + + if err := z.finishDecode(false); err != nil { + return err + } + + if z.invert { + for y := bounds.Min.Y; y < bounds.Max.Y; y++ { + p := (y - bounds.Min.Y) * dst.Stride + invertBytes(dst.Pix[p : p+width]) + } + } + + return nil +} + +// NewReader returns an io.Reader that decodes the CCITT-formatted data in r. +// The resultant byte stream is one bit per pixel (MSB first), with 1 meaning +// white and 0 meaning black. Each row in the result is byte-aligned. +// +// A negative height, such as passing AutoDetectHeight, means that the image +// height is not known in advance. A negative width is invalid. +func NewReader(r io.Reader, order Order, sf SubFormat, width int, height int, opts *Options) io.Reader { + readErr := error(nil) + if width < 0 { + readErr = errInvalidBounds + } else if width > maxWidth { + readErr = errUnsupportedWidth + } + + return &reader{ + br: bitReader{r: r, order: order}, + subFormat: sf, + align: (opts != nil) && opts.Align, + invert: (opts != nil) && opts.Invert, + width: width, + rowsRemaining: height, + readErr: readErr, + } +} diff --git a/vendor/golang.org/x/image/ccitt/table.go b/vendor/golang.org/x/image/ccitt/table.go new file mode 100644 index 0000000..ef7ea9d --- /dev/null +++ b/vendor/golang.org/x/image/ccitt/table.go @@ -0,0 +1,972 @@ +// generated by "go run gen.go". DO NOT EDIT. + +package ccitt + +// Each decodeTable is represented by an array of [2]int16's: a binary tree. +// Each array element (other than element 0, which means invalid) is a branch +// node in that tree. The root node is always element 1 (the second element). +// +// To walk the tree, look at the next bit in the bit stream, using it to select +// the first or second element of the [2]int16. If that int16 is 0, we have an +// invalid code. If it is positive, go to that branch node. If it is negative, +// then we have a leaf node, whose value is the bitwise complement (the ^ +// operator) of that int16. +// +// Comments above each decodeTable also show the same structure visually. The +// "b123" lines show the 123'rd branch node. The "=XXXXX" lines show an invalid +// code. The "=v1234" lines show a leaf node with value 1234. When reading the +// bit stream, a 0 or 1 bit means to go up or down, as you move left to right. +// +// For example, in modeDecodeTable, branch node b005 is three steps up from the +// root node, meaning that we have already seen "000". If the next bit is "0" +// then we move to branch node b006. Otherwise, the next bit is "1", and we +// move to the leaf node v0000 (also known as the modePass constant). Indeed, +// the bits that encode modePass are "0001". +// +// Tables 1, 2 and 3 come from the "ITU-T Recommendation T.6: FACSIMILE CODING +// SCHEMES AND CODING CONTROL FUNCTIONS FOR GROUP 4 FACSIMILE APPARATUS" +// specification: +// +// https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-T.6-198811-I!!PDF-E&type=items + +// modeDecodeTable represents Table 1 and the End-of-Line code. +// +// +=XXXXX +// b009 +-+ +// | +=v0009 +// b007 +-+ +// | | +=v0008 +// b010 | +-+ +// | +=v0005 +// b006 +-+ +// | | +=v0007 +// b008 | +-+ +// | +=v0004 +// b005 +-+ +// | +=v0000 +// b003 +-+ +// | +=v0001 +// b002 +-+ +// | | +=v0006 +// b004 | +-+ +// | +=v0003 +// b001 +-+ +// +=v0002 +var modeDecodeTable = [...][2]int16{ + 0: {0, 0}, + 1: {2, ^2}, + 2: {3, 4}, + 3: {5, ^1}, + 4: {^6, ^3}, + 5: {6, ^0}, + 6: {7, 8}, + 7: {9, 10}, + 8: {^7, ^4}, + 9: {0, ^9}, + 10: {^8, ^5}, +} + +// whiteDecodeTable represents Tables 2 and 3 for a white run. +// +// +=XXXXX +// b059 +-+ +// | | +=v1792 +// b096 | | +-+ +// | | | | +=v1984 +// b100 | | | +-+ +// | | | +=v2048 +// b094 | | +-+ +// | | | | +=v2112 +// b101 | | | | +-+ +// | | | | | +=v2176 +// b097 | | | +-+ +// | | | | +=v2240 +// b102 | | | +-+ +// | | | +=v2304 +// b085 | +-+ +// | | +=v1856 +// b098 | | +-+ +// | | | +=v1920 +// b095 | +-+ +// | | +=v2368 +// b103 | | +-+ +// | | | +=v2432 +// b099 | +-+ +// | | +=v2496 +// b104 | +-+ +// | +=v2560 +// b040 +-+ +// | | +=v0029 +// b060 | +-+ +// | +=v0030 +// b026 +-+ +// | | +=v0045 +// b061 | | +-+ +// | | | +=v0046 +// b041 | +-+ +// | +=v0022 +// b016 +-+ +// | | +=v0023 +// b042 | | +-+ +// | | | | +=v0047 +// b062 | | | +-+ +// | | | +=v0048 +// b027 | +-+ +// | +=v0013 +// b008 +-+ +// | | +=v0020 +// b043 | | +-+ +// | | | | +=v0033 +// b063 | | | +-+ +// | | | +=v0034 +// b028 | | +-+ +// | | | | +=v0035 +// b064 | | | | +-+ +// | | | | | +=v0036 +// b044 | | | +-+ +// | | | | +=v0037 +// b065 | | | +-+ +// | | | +=v0038 +// b017 | +-+ +// | | +=v0019 +// b045 | | +-+ +// | | | | +=v0031 +// b066 | | | +-+ +// | | | +=v0032 +// b029 | +-+ +// | +=v0001 +// b004 +-+ +// | | +=v0012 +// b030 | | +-+ +// | | | | +=v0053 +// b067 | | | | +-+ +// | | | | | +=v0054 +// b046 | | | +-+ +// | | | +=v0026 +// b018 | | +-+ +// | | | | +=v0039 +// b068 | | | | +-+ +// | | | | | +=v0040 +// b047 | | | | +-+ +// | | | | | | +=v0041 +// b069 | | | | | +-+ +// | | | | | +=v0042 +// b031 | | | +-+ +// | | | | +=v0043 +// b070 | | | | +-+ +// | | | | | +=v0044 +// b048 | | | +-+ +// | | | +=v0021 +// b009 | +-+ +// | | +=v0028 +// b049 | | +-+ +// | | | | +=v0061 +// b071 | | | +-+ +// | | | +=v0062 +// b032 | | +-+ +// | | | | +=v0063 +// b072 | | | | +-+ +// | | | | | +=v0000 +// b050 | | | +-+ +// | | | | +=v0320 +// b073 | | | +-+ +// | | | +=v0384 +// b019 | +-+ +// | +=v0010 +// b002 +-+ +// | | +=v0011 +// b020 | | +-+ +// | | | | +=v0027 +// b051 | | | | +-+ +// | | | | | | +=v0059 +// b074 | | | | | +-+ +// | | | | | +=v0060 +// b033 | | | +-+ +// | | | | +=v1472 +// b086 | | | | +-+ +// | | | | | +=v1536 +// b075 | | | | +-+ +// | | | | | | +=v1600 +// b087 | | | | | +-+ +// | | | | | +=v1728 +// b052 | | | +-+ +// | | | +=v0018 +// b010 | | +-+ +// | | | | +=v0024 +// b053 | | | | +-+ +// | | | | | | +=v0049 +// b076 | | | | | +-+ +// | | | | | +=v0050 +// b034 | | | | +-+ +// | | | | | | +=v0051 +// b077 | | | | | | +-+ +// | | | | | | | +=v0052 +// b054 | | | | | +-+ +// | | | | | +=v0025 +// b021 | | | +-+ +// | | | | +=v0055 +// b078 | | | | +-+ +// | | | | | +=v0056 +// b055 | | | | +-+ +// | | | | | | +=v0057 +// b079 | | | | | +-+ +// | | | | | +=v0058 +// b035 | | | +-+ +// | | | +=v0192 +// b005 | +-+ +// | | +=v1664 +// b036 | | +-+ +// | | | | +=v0448 +// b080 | | | | +-+ +// | | | | | +=v0512 +// b056 | | | +-+ +// | | | | +=v0704 +// b088 | | | | +-+ +// | | | | | +=v0768 +// b081 | | | +-+ +// | | | +=v0640 +// b022 | | +-+ +// | | | | +=v0576 +// b082 | | | | +-+ +// | | | | | | +=v0832 +// b089 | | | | | +-+ +// | | | | | +=v0896 +// b057 | | | | +-+ +// | | | | | | +=v0960 +// b090 | | | | | | +-+ +// | | | | | | | +=v1024 +// b083 | | | | | +-+ +// | | | | | | +=v1088 +// b091 | | | | | +-+ +// | | | | | +=v1152 +// b037 | | | +-+ +// | | | | +=v1216 +// b092 | | | | +-+ +// | | | | | +=v1280 +// b084 | | | | +-+ +// | | | | | | +=v1344 +// b093 | | | | | +-+ +// | | | | | +=v1408 +// b058 | | | +-+ +// | | | +=v0256 +// b011 | +-+ +// | +=v0002 +// b001 +-+ +// | +=v0003 +// b012 | +-+ +// | | | +=v0128 +// b023 | | +-+ +// | | +=v0008 +// b006 | +-+ +// | | | +=v0009 +// b024 | | | +-+ +// | | | | | +=v0016 +// b038 | | | | +-+ +// | | | | +=v0017 +// b013 | | +-+ +// | | +=v0004 +// b003 +-+ +// | +=v0005 +// b014 | +-+ +// | | | +=v0014 +// b039 | | | +-+ +// | | | | +=v0015 +// b025 | | +-+ +// | | +=v0064 +// b007 +-+ +// | +=v0006 +// b015 +-+ +// +=v0007 +var whiteDecodeTable = [...][2]int16{ + 0: {0, 0}, + 1: {2, 3}, + 2: {4, 5}, + 3: {6, 7}, + 4: {8, 9}, + 5: {10, 11}, + 6: {12, 13}, + 7: {14, 15}, + 8: {16, 17}, + 9: {18, 19}, + 10: {20, 21}, + 11: {22, ^2}, + 12: {^3, 23}, + 13: {24, ^4}, + 14: {^5, 25}, + 15: {^6, ^7}, + 16: {26, 27}, + 17: {28, 29}, + 18: {30, 31}, + 19: {32, ^10}, + 20: {^11, 33}, + 21: {34, 35}, + 22: {36, 37}, + 23: {^128, ^8}, + 24: {^9, 38}, + 25: {39, ^64}, + 26: {40, 41}, + 27: {42, ^13}, + 28: {43, 44}, + 29: {45, ^1}, + 30: {^12, 46}, + 31: {47, 48}, + 32: {49, 50}, + 33: {51, 52}, + 34: {53, 54}, + 35: {55, ^192}, + 36: {^1664, 56}, + 37: {57, 58}, + 38: {^16, ^17}, + 39: {^14, ^15}, + 40: {59, 60}, + 41: {61, ^22}, + 42: {^23, 62}, + 43: {^20, 63}, + 44: {64, 65}, + 45: {^19, 66}, + 46: {67, ^26}, + 47: {68, 69}, + 48: {70, ^21}, + 49: {^28, 71}, + 50: {72, 73}, + 51: {^27, 74}, + 52: {75, ^18}, + 53: {^24, 76}, + 54: {77, ^25}, + 55: {78, 79}, + 56: {80, 81}, + 57: {82, 83}, + 58: {84, ^256}, + 59: {0, 85}, + 60: {^29, ^30}, + 61: {^45, ^46}, + 62: {^47, ^48}, + 63: {^33, ^34}, + 64: {^35, ^36}, + 65: {^37, ^38}, + 66: {^31, ^32}, + 67: {^53, ^54}, + 68: {^39, ^40}, + 69: {^41, ^42}, + 70: {^43, ^44}, + 71: {^61, ^62}, + 72: {^63, ^0}, + 73: {^320, ^384}, + 74: {^59, ^60}, + 75: {86, 87}, + 76: {^49, ^50}, + 77: {^51, ^52}, + 78: {^55, ^56}, + 79: {^57, ^58}, + 80: {^448, ^512}, + 81: {88, ^640}, + 82: {^576, 89}, + 83: {90, 91}, + 84: {92, 93}, + 85: {94, 95}, + 86: {^1472, ^1536}, + 87: {^1600, ^1728}, + 88: {^704, ^768}, + 89: {^832, ^896}, + 90: {^960, ^1024}, + 91: {^1088, ^1152}, + 92: {^1216, ^1280}, + 93: {^1344, ^1408}, + 94: {96, 97}, + 95: {98, 99}, + 96: {^1792, 100}, + 97: {101, 102}, + 98: {^1856, ^1920}, + 99: {103, 104}, + 100: {^1984, ^2048}, + 101: {^2112, ^2176}, + 102: {^2240, ^2304}, + 103: {^2368, ^2432}, + 104: {^2496, ^2560}, +} + +// blackDecodeTable represents Tables 2 and 3 for a black run. +// +// +=XXXXX +// b017 +-+ +// | | +=v1792 +// b042 | | +-+ +// | | | | +=v1984 +// b063 | | | +-+ +// | | | +=v2048 +// b029 | | +-+ +// | | | | +=v2112 +// b064 | | | | +-+ +// | | | | | +=v2176 +// b043 | | | +-+ +// | | | | +=v2240 +// b065 | | | +-+ +// | | | +=v2304 +// b022 | +-+ +// | | +=v1856 +// b044 | | +-+ +// | | | +=v1920 +// b030 | +-+ +// | | +=v2368 +// b066 | | +-+ +// | | | +=v2432 +// b045 | +-+ +// | | +=v2496 +// b067 | +-+ +// | +=v2560 +// b013 +-+ +// | | +=v0018 +// b031 | | +-+ +// | | | | +=v0052 +// b068 | | | | +-+ +// | | | | | | +=v0640 +// b095 | | | | | +-+ +// | | | | | +=v0704 +// b046 | | | +-+ +// | | | | +=v0768 +// b096 | | | | +-+ +// | | | | | +=v0832 +// b069 | | | +-+ +// | | | +=v0055 +// b023 | | +-+ +// | | | | +=v0056 +// b070 | | | | +-+ +// | | | | | | +=v1280 +// b097 | | | | | +-+ +// | | | | | +=v1344 +// b047 | | | | +-+ +// | | | | | | +=v1408 +// b098 | | | | | | +-+ +// | | | | | | | +=v1472 +// b071 | | | | | +-+ +// | | | | | +=v0059 +// b032 | | | +-+ +// | | | | +=v0060 +// b072 | | | | +-+ +// | | | | | | +=v1536 +// b099 | | | | | +-+ +// | | | | | +=v1600 +// b048 | | | +-+ +// | | | +=v0024 +// b018 | +-+ +// | | +=v0025 +// b049 | | +-+ +// | | | | +=v1664 +// b100 | | | | +-+ +// | | | | | +=v1728 +// b073 | | | +-+ +// | | | +=v0320 +// b033 | | +-+ +// | | | | +=v0384 +// b074 | | | | +-+ +// | | | | | +=v0448 +// b050 | | | +-+ +// | | | | +=v0512 +// b101 | | | | +-+ +// | | | | | +=v0576 +// b075 | | | +-+ +// | | | +=v0053 +// b024 | +-+ +// | | +=v0054 +// b076 | | +-+ +// | | | | +=v0896 +// b102 | | | +-+ +// | | | +=v0960 +// b051 | | +-+ +// | | | | +=v1024 +// b103 | | | | +-+ +// | | | | | +=v1088 +// b077 | | | +-+ +// | | | | +=v1152 +// b104 | | | +-+ +// | | | +=v1216 +// b034 | +-+ +// | +=v0064 +// b010 +-+ +// | | +=v0013 +// b019 | | +-+ +// | | | | +=v0023 +// b052 | | | | +-+ +// | | | | | | +=v0050 +// b078 | | | | | +-+ +// | | | | | +=v0051 +// b035 | | | | +-+ +// | | | | | | +=v0044 +// b079 | | | | | | +-+ +// | | | | | | | +=v0045 +// b053 | | | | | +-+ +// | | | | | | +=v0046 +// b080 | | | | | +-+ +// | | | | | +=v0047 +// b025 | | | +-+ +// | | | | +=v0057 +// b081 | | | | +-+ +// | | | | | +=v0058 +// b054 | | | | +-+ +// | | | | | | +=v0061 +// b082 | | | | | +-+ +// | | | | | +=v0256 +// b036 | | | +-+ +// | | | +=v0016 +// b014 | +-+ +// | | +=v0017 +// b037 | | +-+ +// | | | | +=v0048 +// b083 | | | | +-+ +// | | | | | +=v0049 +// b055 | | | +-+ +// | | | | +=v0062 +// b084 | | | +-+ +// | | | +=v0063 +// b026 | | +-+ +// | | | | +=v0030 +// b085 | | | | +-+ +// | | | | | +=v0031 +// b056 | | | | +-+ +// | | | | | | +=v0032 +// b086 | | | | | +-+ +// | | | | | +=v0033 +// b038 | | | +-+ +// | | | | +=v0040 +// b087 | | | | +-+ +// | | | | | +=v0041 +// b057 | | | +-+ +// | | | +=v0022 +// b020 | +-+ +// | +=v0014 +// b008 +-+ +// | | +=v0010 +// b015 | | +-+ +// | | | +=v0011 +// b011 | +-+ +// | | +=v0015 +// b027 | | +-+ +// | | | | +=v0128 +// b088 | | | | +-+ +// | | | | | +=v0192 +// b058 | | | | +-+ +// | | | | | | +=v0026 +// b089 | | | | | +-+ +// | | | | | +=v0027 +// b039 | | | +-+ +// | | | | +=v0028 +// b090 | | | | +-+ +// | | | | | +=v0029 +// b059 | | | +-+ +// | | | +=v0019 +// b021 | | +-+ +// | | | | +=v0020 +// b060 | | | | +-+ +// | | | | | | +=v0034 +// b091 | | | | | +-+ +// | | | | | +=v0035 +// b040 | | | | +-+ +// | | | | | | +=v0036 +// b092 | | | | | | +-+ +// | | | | | | | +=v0037 +// b061 | | | | | +-+ +// | | | | | | +=v0038 +// b093 | | | | | +-+ +// | | | | | +=v0039 +// b028 | | | +-+ +// | | | | +=v0021 +// b062 | | | | +-+ +// | | | | | | +=v0042 +// b094 | | | | | +-+ +// | | | | | +=v0043 +// b041 | | | +-+ +// | | | +=v0000 +// b016 | +-+ +// | +=v0012 +// b006 +-+ +// | | +=v0009 +// b012 | | +-+ +// | | | +=v0008 +// b009 | +-+ +// | +=v0007 +// b004 +-+ +// | | +=v0006 +// b007 | +-+ +// | +=v0005 +// b002 +-+ +// | | +=v0001 +// b005 | +-+ +// | +=v0004 +// b001 +-+ +// | +=v0003 +// b003 +-+ +// +=v0002 +var blackDecodeTable = [...][2]int16{ + 0: {0, 0}, + 1: {2, 3}, + 2: {4, 5}, + 3: {^3, ^2}, + 4: {6, 7}, + 5: {^1, ^4}, + 6: {8, 9}, + 7: {^6, ^5}, + 8: {10, 11}, + 9: {12, ^7}, + 10: {13, 14}, + 11: {15, 16}, + 12: {^9, ^8}, + 13: {17, 18}, + 14: {19, 20}, + 15: {^10, ^11}, + 16: {21, ^12}, + 17: {0, 22}, + 18: {23, 24}, + 19: {^13, 25}, + 20: {26, ^14}, + 21: {27, 28}, + 22: {29, 30}, + 23: {31, 32}, + 24: {33, 34}, + 25: {35, 36}, + 26: {37, 38}, + 27: {^15, 39}, + 28: {40, 41}, + 29: {42, 43}, + 30: {44, 45}, + 31: {^18, 46}, + 32: {47, 48}, + 33: {49, 50}, + 34: {51, ^64}, + 35: {52, 53}, + 36: {54, ^16}, + 37: {^17, 55}, + 38: {56, 57}, + 39: {58, 59}, + 40: {60, 61}, + 41: {62, ^0}, + 42: {^1792, 63}, + 43: {64, 65}, + 44: {^1856, ^1920}, + 45: {66, 67}, + 46: {68, 69}, + 47: {70, 71}, + 48: {72, ^24}, + 49: {^25, 73}, + 50: {74, 75}, + 51: {76, 77}, + 52: {^23, 78}, + 53: {79, 80}, + 54: {81, 82}, + 55: {83, 84}, + 56: {85, 86}, + 57: {87, ^22}, + 58: {88, 89}, + 59: {90, ^19}, + 60: {^20, 91}, + 61: {92, 93}, + 62: {^21, 94}, + 63: {^1984, ^2048}, + 64: {^2112, ^2176}, + 65: {^2240, ^2304}, + 66: {^2368, ^2432}, + 67: {^2496, ^2560}, + 68: {^52, 95}, + 69: {96, ^55}, + 70: {^56, 97}, + 71: {98, ^59}, + 72: {^60, 99}, + 73: {100, ^320}, + 74: {^384, ^448}, + 75: {101, ^53}, + 76: {^54, 102}, + 77: {103, 104}, + 78: {^50, ^51}, + 79: {^44, ^45}, + 80: {^46, ^47}, + 81: {^57, ^58}, + 82: {^61, ^256}, + 83: {^48, ^49}, + 84: {^62, ^63}, + 85: {^30, ^31}, + 86: {^32, ^33}, + 87: {^40, ^41}, + 88: {^128, ^192}, + 89: {^26, ^27}, + 90: {^28, ^29}, + 91: {^34, ^35}, + 92: {^36, ^37}, + 93: {^38, ^39}, + 94: {^42, ^43}, + 95: {^640, ^704}, + 96: {^768, ^832}, + 97: {^1280, ^1344}, + 98: {^1408, ^1472}, + 99: {^1536, ^1600}, + 100: {^1664, ^1728}, + 101: {^512, ^576}, + 102: {^896, ^960}, + 103: {^1024, ^1088}, + 104: {^1152, ^1216}, +} + +const maxCodeLength = 13 + +// Each encodeTable is represented by an array of bitStrings. + +// bitString is a pair of uint32 values representing a bit code. +// The nBits low bits of bits make up the actual bit code. +// Eg. bitString{0x0004, 8} represents the bitcode "00000100". +type bitString struct { + bits uint32 + nBits uint32 +} + +// modeEncodeTable represents Table 1 and the End-of-Line code. +var modeEncodeTable = [...]bitString{ + 0: {0x0001, 4}, // "0001" + 1: {0x0001, 3}, // "001" + 2: {0x0001, 1}, // "1" + 3: {0x0003, 3}, // "011" + 4: {0x0003, 6}, // "000011" + 5: {0x0003, 7}, // "0000011" + 6: {0x0002, 3}, // "010" + 7: {0x0002, 6}, // "000010" + 8: {0x0002, 7}, // "0000010" + 9: {0x0001, 7}, // "0000001" +} + +// whiteEncodeTable2 represents Table 2 for a white run. +var whiteEncodeTable2 = [...]bitString{ + 0: {0x0035, 8}, // "00110101" + 1: {0x0007, 6}, // "000111" + 2: {0x0007, 4}, // "0111" + 3: {0x0008, 4}, // "1000" + 4: {0x000b, 4}, // "1011" + 5: {0x000c, 4}, // "1100" + 6: {0x000e, 4}, // "1110" + 7: {0x000f, 4}, // "1111" + 8: {0x0013, 5}, // "10011" + 9: {0x0014, 5}, // "10100" + 10: {0x0007, 5}, // "00111" + 11: {0x0008, 5}, // "01000" + 12: {0x0008, 6}, // "001000" + 13: {0x0003, 6}, // "000011" + 14: {0x0034, 6}, // "110100" + 15: {0x0035, 6}, // "110101" + 16: {0x002a, 6}, // "101010" + 17: {0x002b, 6}, // "101011" + 18: {0x0027, 7}, // "0100111" + 19: {0x000c, 7}, // "0001100" + 20: {0x0008, 7}, // "0001000" + 21: {0x0017, 7}, // "0010111" + 22: {0x0003, 7}, // "0000011" + 23: {0x0004, 7}, // "0000100" + 24: {0x0028, 7}, // "0101000" + 25: {0x002b, 7}, // "0101011" + 26: {0x0013, 7}, // "0010011" + 27: {0x0024, 7}, // "0100100" + 28: {0x0018, 7}, // "0011000" + 29: {0x0002, 8}, // "00000010" + 30: {0x0003, 8}, // "00000011" + 31: {0x001a, 8}, // "00011010" + 32: {0x001b, 8}, // "00011011" + 33: {0x0012, 8}, // "00010010" + 34: {0x0013, 8}, // "00010011" + 35: {0x0014, 8}, // "00010100" + 36: {0x0015, 8}, // "00010101" + 37: {0x0016, 8}, // "00010110" + 38: {0x0017, 8}, // "00010111" + 39: {0x0028, 8}, // "00101000" + 40: {0x0029, 8}, // "00101001" + 41: {0x002a, 8}, // "00101010" + 42: {0x002b, 8}, // "00101011" + 43: {0x002c, 8}, // "00101100" + 44: {0x002d, 8}, // "00101101" + 45: {0x0004, 8}, // "00000100" + 46: {0x0005, 8}, // "00000101" + 47: {0x000a, 8}, // "00001010" + 48: {0x000b, 8}, // "00001011" + 49: {0x0052, 8}, // "01010010" + 50: {0x0053, 8}, // "01010011" + 51: {0x0054, 8}, // "01010100" + 52: {0x0055, 8}, // "01010101" + 53: {0x0024, 8}, // "00100100" + 54: {0x0025, 8}, // "00100101" + 55: {0x0058, 8}, // "01011000" + 56: {0x0059, 8}, // "01011001" + 57: {0x005a, 8}, // "01011010" + 58: {0x005b, 8}, // "01011011" + 59: {0x004a, 8}, // "01001010" + 60: {0x004b, 8}, // "01001011" + 61: {0x0032, 8}, // "00110010" + 62: {0x0033, 8}, // "00110011" + 63: {0x0034, 8}, // "00110100" +} + +// whiteEncodeTable3 represents Table 3 for a white run. +var whiteEncodeTable3 = [...]bitString{ + 0: {0x001b, 5}, // "11011" + 1: {0x0012, 5}, // "10010" + 2: {0x0017, 6}, // "010111" + 3: {0x0037, 7}, // "0110111" + 4: {0x0036, 8}, // "00110110" + 5: {0x0037, 8}, // "00110111" + 6: {0x0064, 8}, // "01100100" + 7: {0x0065, 8}, // "01100101" + 8: {0x0068, 8}, // "01101000" + 9: {0x0067, 8}, // "01100111" + 10: {0x00cc, 9}, // "011001100" + 11: {0x00cd, 9}, // "011001101" + 12: {0x00d2, 9}, // "011010010" + 13: {0x00d3, 9}, // "011010011" + 14: {0x00d4, 9}, // "011010100" + 15: {0x00d5, 9}, // "011010101" + 16: {0x00d6, 9}, // "011010110" + 17: {0x00d7, 9}, // "011010111" + 18: {0x00d8, 9}, // "011011000" + 19: {0x00d9, 9}, // "011011001" + 20: {0x00da, 9}, // "011011010" + 21: {0x00db, 9}, // "011011011" + 22: {0x0098, 9}, // "010011000" + 23: {0x0099, 9}, // "010011001" + 24: {0x009a, 9}, // "010011010" + 25: {0x0018, 6}, // "011000" + 26: {0x009b, 9}, // "010011011" + 27: {0x0008, 11}, // "00000001000" + 28: {0x000c, 11}, // "00000001100" + 29: {0x000d, 11}, // "00000001101" + 30: {0x0012, 12}, // "000000010010" + 31: {0x0013, 12}, // "000000010011" + 32: {0x0014, 12}, // "000000010100" + 33: {0x0015, 12}, // "000000010101" + 34: {0x0016, 12}, // "000000010110" + 35: {0x0017, 12}, // "000000010111" + 36: {0x001c, 12}, // "000000011100" + 37: {0x001d, 12}, // "000000011101" + 38: {0x001e, 12}, // "000000011110" + 39: {0x001f, 12}, // "000000011111" +} + +// blackEncodeTable2 represents Table 2 for a black run. +var blackEncodeTable2 = [...]bitString{ + 0: {0x0037, 10}, // "0000110111" + 1: {0x0002, 3}, // "010" + 2: {0x0003, 2}, // "11" + 3: {0x0002, 2}, // "10" + 4: {0x0003, 3}, // "011" + 5: {0x0003, 4}, // "0011" + 6: {0x0002, 4}, // "0010" + 7: {0x0003, 5}, // "00011" + 8: {0x0005, 6}, // "000101" + 9: {0x0004, 6}, // "000100" + 10: {0x0004, 7}, // "0000100" + 11: {0x0005, 7}, // "0000101" + 12: {0x0007, 7}, // "0000111" + 13: {0x0004, 8}, // "00000100" + 14: {0x0007, 8}, // "00000111" + 15: {0x0018, 9}, // "000011000" + 16: {0x0017, 10}, // "0000010111" + 17: {0x0018, 10}, // "0000011000" + 18: {0x0008, 10}, // "0000001000" + 19: {0x0067, 11}, // "00001100111" + 20: {0x0068, 11}, // "00001101000" + 21: {0x006c, 11}, // "00001101100" + 22: {0x0037, 11}, // "00000110111" + 23: {0x0028, 11}, // "00000101000" + 24: {0x0017, 11}, // "00000010111" + 25: {0x0018, 11}, // "00000011000" + 26: {0x00ca, 12}, // "000011001010" + 27: {0x00cb, 12}, // "000011001011" + 28: {0x00cc, 12}, // "000011001100" + 29: {0x00cd, 12}, // "000011001101" + 30: {0x0068, 12}, // "000001101000" + 31: {0x0069, 12}, // "000001101001" + 32: {0x006a, 12}, // "000001101010" + 33: {0x006b, 12}, // "000001101011" + 34: {0x00d2, 12}, // "000011010010" + 35: {0x00d3, 12}, // "000011010011" + 36: {0x00d4, 12}, // "000011010100" + 37: {0x00d5, 12}, // "000011010101" + 38: {0x00d6, 12}, // "000011010110" + 39: {0x00d7, 12}, // "000011010111" + 40: {0x006c, 12}, // "000001101100" + 41: {0x006d, 12}, // "000001101101" + 42: {0x00da, 12}, // "000011011010" + 43: {0x00db, 12}, // "000011011011" + 44: {0x0054, 12}, // "000001010100" + 45: {0x0055, 12}, // "000001010101" + 46: {0x0056, 12}, // "000001010110" + 47: {0x0057, 12}, // "000001010111" + 48: {0x0064, 12}, // "000001100100" + 49: {0x0065, 12}, // "000001100101" + 50: {0x0052, 12}, // "000001010010" + 51: {0x0053, 12}, // "000001010011" + 52: {0x0024, 12}, // "000000100100" + 53: {0x0037, 12}, // "000000110111" + 54: {0x0038, 12}, // "000000111000" + 55: {0x0027, 12}, // "000000100111" + 56: {0x0028, 12}, // "000000101000" + 57: {0x0058, 12}, // "000001011000" + 58: {0x0059, 12}, // "000001011001" + 59: {0x002b, 12}, // "000000101011" + 60: {0x002c, 12}, // "000000101100" + 61: {0x005a, 12}, // "000001011010" + 62: {0x0066, 12}, // "000001100110" + 63: {0x0067, 12}, // "000001100111" +} + +// blackEncodeTable3 represents Table 3 for a black run. +var blackEncodeTable3 = [...]bitString{ + 0: {0x000f, 10}, // "0000001111" + 1: {0x00c8, 12}, // "000011001000" + 2: {0x00c9, 12}, // "000011001001" + 3: {0x005b, 12}, // "000001011011" + 4: {0x0033, 12}, // "000000110011" + 5: {0x0034, 12}, // "000000110100" + 6: {0x0035, 12}, // "000000110101" + 7: {0x006c, 13}, // "0000001101100" + 8: {0x006d, 13}, // "0000001101101" + 9: {0x004a, 13}, // "0000001001010" + 10: {0x004b, 13}, // "0000001001011" + 11: {0x004c, 13}, // "0000001001100" + 12: {0x004d, 13}, // "0000001001101" + 13: {0x0072, 13}, // "0000001110010" + 14: {0x0073, 13}, // "0000001110011" + 15: {0x0074, 13}, // "0000001110100" + 16: {0x0075, 13}, // "0000001110101" + 17: {0x0076, 13}, // "0000001110110" + 18: {0x0077, 13}, // "0000001110111" + 19: {0x0052, 13}, // "0000001010010" + 20: {0x0053, 13}, // "0000001010011" + 21: {0x0054, 13}, // "0000001010100" + 22: {0x0055, 13}, // "0000001010101" + 23: {0x005a, 13}, // "0000001011010" + 24: {0x005b, 13}, // "0000001011011" + 25: {0x0064, 13}, // "0000001100100" + 26: {0x0065, 13}, // "0000001100101" + 27: {0x0008, 11}, // "00000001000" + 28: {0x000c, 11}, // "00000001100" + 29: {0x000d, 11}, // "00000001101" + 30: {0x0012, 12}, // "000000010010" + 31: {0x0013, 12}, // "000000010011" + 32: {0x0014, 12}, // "000000010100" + 33: {0x0015, 12}, // "000000010101" + 34: {0x0016, 12}, // "000000010110" + 35: {0x0017, 12}, // "000000010111" + 36: {0x001c, 12}, // "000000011100" + 37: {0x001d, 12}, // "000000011101" + 38: {0x001e, 12}, // "000000011110" + 39: {0x001f, 12}, // "000000011111" +} + +// COPY PASTE table.go BEGIN + +const ( + modePass = iota // Pass + modeH // Horizontal + modeV0 // Vertical-0 + modeVR1 // Vertical-Right-1 + modeVR2 // Vertical-Right-2 + modeVR3 // Vertical-Right-3 + modeVL1 // Vertical-Left-1 + modeVL2 // Vertical-Left-2 + modeVL3 // Vertical-Left-3 + modeExt // Extension +) + +// COPY PASTE table.go END diff --git a/vendor/golang.org/x/image/ccitt/writer.go b/vendor/golang.org/x/image/ccitt/writer.go new file mode 100644 index 0000000..87130ab --- /dev/null +++ b/vendor/golang.org/x/image/ccitt/writer.go @@ -0,0 +1,102 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ccitt + +import ( + "encoding/binary" + "io" +) + +type bitWriter struct { + w io.Writer + + // order is whether to process w's bytes LSB first or MSB first. + order Order + + // The high nBits bits of the bits field hold encoded bits to be written to w. + bits uint64 + nBits uint32 + + // bytes[:bw] holds encoded bytes not yet written to w. + // Overflow protection is ensured by using a multiple of 8 as bytes length. + bw uint32 + bytes [1024]uint8 +} + +// flushBits copies 64 bits from b.bits to b.bytes. If b.bytes is then full, it +// is written to b.w. +func (b *bitWriter) flushBits() error { + binary.BigEndian.PutUint64(b.bytes[b.bw:], b.bits) + b.bits = 0 + b.nBits = 0 + b.bw += 8 + if b.bw < uint32(len(b.bytes)) { + return nil + } + b.bw = 0 + if b.order != MSB { + reverseBitsWithinBytes(b.bytes[:]) + } + _, err := b.w.Write(b.bytes[:]) + return err +} + +// close finalizes a bitcode stream by writing any +// pending bits to bitWriter's underlying io.Writer. +func (b *bitWriter) close() error { + // Write any encoded bits to bytes. + if b.nBits > 0 { + binary.BigEndian.PutUint64(b.bytes[b.bw:], b.bits) + b.bw += (b.nBits + 7) >> 3 + } + + if b.order != MSB { + reverseBitsWithinBytes(b.bytes[:b.bw]) + } + + // Write b.bw bytes to b.w. + _, err := b.w.Write(b.bytes[:b.bw]) + return err +} + +// alignToByteBoundary rounds b.nBits up to a multiple of 8. +// If all 64 bits are used, flush them to bitWriter's bytes. +func (b *bitWriter) alignToByteBoundary() error { + if b.nBits = (b.nBits + 7) &^ 7; b.nBits == 64 { + return b.flushBits() + } + return nil +} + +// writeCode writes a variable length bitcode to b's underlying io.Writer. +func (b *bitWriter) writeCode(bs bitString) error { + bits := bs.bits + nBits := bs.nBits + if 64-b.nBits >= nBits { + // b.bits has sufficient room for storing nBits bits. + b.bits |= uint64(bits) << (64 - nBits - b.nBits) + b.nBits += nBits + if b.nBits == 64 { + return b.flushBits() + } + return nil + } + + // Number of leading bits that fill b.bits. + i := 64 - b.nBits + + // Fill b.bits then flush and write remaining bits. + b.bits |= uint64(bits) >> (nBits - i) + b.nBits = 64 + + if err := b.flushBits(); err != nil { + return err + } + + nBits -= i + b.bits = uint64(bits) << (64 - nBits) + b.nBits = nBits + return nil +} diff --git a/vendor/gopkg.in/yaml.v2/.travis.yml b/vendor/gopkg.in/yaml.v2/.travis.yml new file mode 100644 index 0000000..055480b --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/.travis.yml @@ -0,0 +1,16 @@ +language: go + +go: + - "1.4.x" + - "1.5.x" + - "1.6.x" + - "1.7.x" + - "1.8.x" + - "1.9.x" + - "1.10.x" + - "1.11.x" + - "1.12.x" + - "1.13.x" + - "tip" + +go_import_path: gopkg.in/yaml.v2 diff --git a/vendor/gopkg.in/yaml.v2/LICENSE b/vendor/gopkg.in/yaml.v2/LICENSE new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/gopkg.in/yaml.v2/LICENSE.libyaml b/vendor/gopkg.in/yaml.v2/LICENSE.libyaml new file mode 100644 index 0000000..8da58fb --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/LICENSE.libyaml @@ -0,0 +1,31 @@ +The following files were ported to Go from C files of libyaml, and thus +are still covered by their original copyright and license: + + apic.go + emitterc.go + parserc.go + readerc.go + scannerc.go + writerc.go + yamlh.go + yamlprivateh.go + +Copyright (c) 2006 Kirill Simonov + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/gopkg.in/yaml.v2/NOTICE b/vendor/gopkg.in/yaml.v2/NOTICE new file mode 100644 index 0000000..866d74a --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/NOTICE @@ -0,0 +1,13 @@ +Copyright 2011-2016 Canonical Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/gopkg.in/yaml.v2/README.md b/vendor/gopkg.in/yaml.v2/README.md new file mode 100644 index 0000000..b50c6e8 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/README.md @@ -0,0 +1,133 @@ +# YAML support for the Go language + +Introduction +------------ + +The yaml package enables Go programs to comfortably encode and decode YAML +values. It was developed within [Canonical](https://www.canonical.com) as +part of the [juju](https://juju.ubuntu.com) project, and is based on a +pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) +C library to parse and generate YAML data quickly and reliably. + +Compatibility +------------- + +The yaml package supports most of YAML 1.1 and 1.2, including support for +anchors, tags, map merging, etc. Multi-document unmarshalling is not yet +implemented, and base-60 floats from YAML 1.1 are purposefully not +supported since they're a poor design and are gone in YAML 1.2. + +Installation and usage +---------------------- + +The import path for the package is *gopkg.in/yaml.v2*. + +To install it, run: + + go get gopkg.in/yaml.v2 + +API documentation +----------------- + +If opened in a browser, the import path itself leads to the API documentation: + + * [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) + +API stability +------------- + +The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in). + + +License +------- + +The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details. + + +Example +------- + +```Go +package main + +import ( + "fmt" + "log" + + "gopkg.in/yaml.v2" +) + +var data = ` +a: Easy! +b: + c: 2 + d: [3, 4] +` + +// Note: struct fields must be public in order for unmarshal to +// correctly populate the data. +type T struct { + A string + B struct { + RenamedC int `yaml:"c"` + D []int `yaml:",flow"` + } +} + +func main() { + t := T{} + + err := yaml.Unmarshal([]byte(data), &t) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- t:\n%v\n\n", t) + + d, err := yaml.Marshal(&t) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- t dump:\n%s\n\n", string(d)) + + m := make(map[interface{}]interface{}) + + err = yaml.Unmarshal([]byte(data), &m) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- m:\n%v\n\n", m) + + d, err = yaml.Marshal(&m) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- m dump:\n%s\n\n", string(d)) +} +``` + +This example will generate the following output: + +``` +--- t: +{Easy! {2 [3 4]}} + +--- t dump: +a: Easy! +b: + c: 2 + d: [3, 4] + + +--- m: +map[a:Easy! b:map[c:2 d:[3 4]]] + +--- m dump: +a: Easy! +b: + c: 2 + d: + - 3 + - 4 +``` + diff --git a/vendor/gopkg.in/yaml.v2/apic.go b/vendor/gopkg.in/yaml.v2/apic.go new file mode 100644 index 0000000..d2c2308 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/apic.go @@ -0,0 +1,740 @@ +package yaml + +import ( + "io" +) + +func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) { + //fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens)) + + // Check if we can move the queue at the beginning of the buffer. + if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) { + if parser.tokens_head != len(parser.tokens) { + copy(parser.tokens, parser.tokens[parser.tokens_head:]) + } + parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head] + parser.tokens_head = 0 + } + parser.tokens = append(parser.tokens, *token) + if pos < 0 { + return + } + copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:]) + parser.tokens[parser.tokens_head+pos] = *token +} + +// Create a new parser object. +func yaml_parser_initialize(parser *yaml_parser_t) bool { + *parser = yaml_parser_t{ + raw_buffer: make([]byte, 0, input_raw_buffer_size), + buffer: make([]byte, 0, input_buffer_size), + } + return true +} + +// Destroy a parser object. +func yaml_parser_delete(parser *yaml_parser_t) { + *parser = yaml_parser_t{} +} + +// String read handler. +func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { + if parser.input_pos == len(parser.input) { + return 0, io.EOF + } + n = copy(buffer, parser.input[parser.input_pos:]) + parser.input_pos += n + return n, nil +} + +// Reader read handler. +func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { + return parser.input_reader.Read(buffer) +} + +// Set a string input. +func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) { + if parser.read_handler != nil { + panic("must set the input source only once") + } + parser.read_handler = yaml_string_read_handler + parser.input = input + parser.input_pos = 0 +} + +// Set a file input. +func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) { + if parser.read_handler != nil { + panic("must set the input source only once") + } + parser.read_handler = yaml_reader_read_handler + parser.input_reader = r +} + +// Set the source encoding. +func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) { + if parser.encoding != yaml_ANY_ENCODING { + panic("must set the encoding only once") + } + parser.encoding = encoding +} + +// Create a new emitter object. +func yaml_emitter_initialize(emitter *yaml_emitter_t) { + *emitter = yaml_emitter_t{ + buffer: make([]byte, output_buffer_size), + raw_buffer: make([]byte, 0, output_raw_buffer_size), + states: make([]yaml_emitter_state_t, 0, initial_stack_size), + events: make([]yaml_event_t, 0, initial_queue_size), + best_width: -1, + } +} + +// Destroy an emitter object. +func yaml_emitter_delete(emitter *yaml_emitter_t) { + *emitter = yaml_emitter_t{} +} + +// String write handler. +func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error { + *emitter.output_buffer = append(*emitter.output_buffer, buffer...) + return nil +} + +// yaml_writer_write_handler uses emitter.output_writer to write the +// emitted text. +func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error { + _, err := emitter.output_writer.Write(buffer) + return err +} + +// Set a string output. +func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) { + if emitter.write_handler != nil { + panic("must set the output target only once") + } + emitter.write_handler = yaml_string_write_handler + emitter.output_buffer = output_buffer +} + +// Set a file output. +func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) { + if emitter.write_handler != nil { + panic("must set the output target only once") + } + emitter.write_handler = yaml_writer_write_handler + emitter.output_writer = w +} + +// Set the output encoding. +func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) { + if emitter.encoding != yaml_ANY_ENCODING { + panic("must set the output encoding only once") + } + emitter.encoding = encoding +} + +// Set the canonical output style. +func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) { + emitter.canonical = canonical +} + +//// Set the indentation increment. +func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) { + if indent < 2 || indent > 9 { + indent = 2 + } + emitter.best_indent = indent +} + +// Set the preferred line width. +func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) { + if width < 0 { + width = -1 + } + emitter.best_width = width +} + +// Set if unescaped non-ASCII characters are allowed. +func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) { + emitter.unicode = unicode +} + +// Set the preferred line break character. +func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) { + emitter.line_break = line_break +} + +///* +// * Destroy a token object. +// */ +// +//YAML_DECLARE(void) +//yaml_token_delete(yaml_token_t *token) +//{ +// assert(token); // Non-NULL token object expected. +// +// switch (token.type) +// { +// case YAML_TAG_DIRECTIVE_TOKEN: +// yaml_free(token.data.tag_directive.handle); +// yaml_free(token.data.tag_directive.prefix); +// break; +// +// case YAML_ALIAS_TOKEN: +// yaml_free(token.data.alias.value); +// break; +// +// case YAML_ANCHOR_TOKEN: +// yaml_free(token.data.anchor.value); +// break; +// +// case YAML_TAG_TOKEN: +// yaml_free(token.data.tag.handle); +// yaml_free(token.data.tag.suffix); +// break; +// +// case YAML_SCALAR_TOKEN: +// yaml_free(token.data.scalar.value); +// break; +// +// default: +// break; +// } +// +// memset(token, 0, sizeof(yaml_token_t)); +//} +// +///* +// * Check if a string is a valid UTF-8 sequence. +// * +// * Check 'reader.c' for more details on UTF-8 encoding. +// */ +// +//static int +//yaml_check_utf8(yaml_char_t *start, size_t length) +//{ +// yaml_char_t *end = start+length; +// yaml_char_t *pointer = start; +// +// while (pointer < end) { +// unsigned char octet; +// unsigned int width; +// unsigned int value; +// size_t k; +// +// octet = pointer[0]; +// width = (octet & 0x80) == 0x00 ? 1 : +// (octet & 0xE0) == 0xC0 ? 2 : +// (octet & 0xF0) == 0xE0 ? 3 : +// (octet & 0xF8) == 0xF0 ? 4 : 0; +// value = (octet & 0x80) == 0x00 ? octet & 0x7F : +// (octet & 0xE0) == 0xC0 ? octet & 0x1F : +// (octet & 0xF0) == 0xE0 ? octet & 0x0F : +// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; +// if (!width) return 0; +// if (pointer+width > end) return 0; +// for (k = 1; k < width; k ++) { +// octet = pointer[k]; +// if ((octet & 0xC0) != 0x80) return 0; +// value = (value << 6) + (octet & 0x3F); +// } +// if (!((width == 1) || +// (width == 2 && value >= 0x80) || +// (width == 3 && value >= 0x800) || +// (width == 4 && value >= 0x10000))) return 0; +// +// pointer += width; +// } +// +// return 1; +//} +// + +// Create STREAM-START. +func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) { + *event = yaml_event_t{ + typ: yaml_STREAM_START_EVENT, + encoding: encoding, + } +} + +// Create STREAM-END. +func yaml_stream_end_event_initialize(event *yaml_event_t) { + *event = yaml_event_t{ + typ: yaml_STREAM_END_EVENT, + } +} + +// Create DOCUMENT-START. +func yaml_document_start_event_initialize( + event *yaml_event_t, + version_directive *yaml_version_directive_t, + tag_directives []yaml_tag_directive_t, + implicit bool, +) { + *event = yaml_event_t{ + typ: yaml_DOCUMENT_START_EVENT, + version_directive: version_directive, + tag_directives: tag_directives, + implicit: implicit, + } +} + +// Create DOCUMENT-END. +func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) { + *event = yaml_event_t{ + typ: yaml_DOCUMENT_END_EVENT, + implicit: implicit, + } +} + +///* +// * Create ALIAS. +// */ +// +//YAML_DECLARE(int) +//yaml_alias_event_initialize(event *yaml_event_t, anchor *yaml_char_t) +//{ +// mark yaml_mark_t = { 0, 0, 0 } +// anchor_copy *yaml_char_t = NULL +// +// assert(event) // Non-NULL event object is expected. +// assert(anchor) // Non-NULL anchor is expected. +// +// if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0 +// +// anchor_copy = yaml_strdup(anchor) +// if (!anchor_copy) +// return 0 +// +// ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark) +// +// return 1 +//} + +// Create SCALAR. +func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool { + *event = yaml_event_t{ + typ: yaml_SCALAR_EVENT, + anchor: anchor, + tag: tag, + value: value, + implicit: plain_implicit, + quoted_implicit: quoted_implicit, + style: yaml_style_t(style), + } + return true +} + +// Create SEQUENCE-START. +func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool { + *event = yaml_event_t{ + typ: yaml_SEQUENCE_START_EVENT, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(style), + } + return true +} + +// Create SEQUENCE-END. +func yaml_sequence_end_event_initialize(event *yaml_event_t) bool { + *event = yaml_event_t{ + typ: yaml_SEQUENCE_END_EVENT, + } + return true +} + +// Create MAPPING-START. +func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) { + *event = yaml_event_t{ + typ: yaml_MAPPING_START_EVENT, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(style), + } +} + +// Create MAPPING-END. +func yaml_mapping_end_event_initialize(event *yaml_event_t) { + *event = yaml_event_t{ + typ: yaml_MAPPING_END_EVENT, + } +} + +// Destroy an event object. +func yaml_event_delete(event *yaml_event_t) { + *event = yaml_event_t{} +} + +///* +// * Create a document object. +// */ +// +//YAML_DECLARE(int) +//yaml_document_initialize(document *yaml_document_t, +// version_directive *yaml_version_directive_t, +// tag_directives_start *yaml_tag_directive_t, +// tag_directives_end *yaml_tag_directive_t, +// start_implicit int, end_implicit int) +//{ +// struct { +// error yaml_error_type_t +// } context +// struct { +// start *yaml_node_t +// end *yaml_node_t +// top *yaml_node_t +// } nodes = { NULL, NULL, NULL } +// version_directive_copy *yaml_version_directive_t = NULL +// struct { +// start *yaml_tag_directive_t +// end *yaml_tag_directive_t +// top *yaml_tag_directive_t +// } tag_directives_copy = { NULL, NULL, NULL } +// value yaml_tag_directive_t = { NULL, NULL } +// mark yaml_mark_t = { 0, 0, 0 } +// +// assert(document) // Non-NULL document object is expected. +// assert((tag_directives_start && tag_directives_end) || +// (tag_directives_start == tag_directives_end)) +// // Valid tag directives are expected. +// +// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error +// +// if (version_directive) { +// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)) +// if (!version_directive_copy) goto error +// version_directive_copy.major = version_directive.major +// version_directive_copy.minor = version_directive.minor +// } +// +// if (tag_directives_start != tag_directives_end) { +// tag_directive *yaml_tag_directive_t +// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) +// goto error +// for (tag_directive = tag_directives_start +// tag_directive != tag_directives_end; tag_directive ++) { +// assert(tag_directive.handle) +// assert(tag_directive.prefix) +// if (!yaml_check_utf8(tag_directive.handle, +// strlen((char *)tag_directive.handle))) +// goto error +// if (!yaml_check_utf8(tag_directive.prefix, +// strlen((char *)tag_directive.prefix))) +// goto error +// value.handle = yaml_strdup(tag_directive.handle) +// value.prefix = yaml_strdup(tag_directive.prefix) +// if (!value.handle || !value.prefix) goto error +// if (!PUSH(&context, tag_directives_copy, value)) +// goto error +// value.handle = NULL +// value.prefix = NULL +// } +// } +// +// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, +// tag_directives_copy.start, tag_directives_copy.top, +// start_implicit, end_implicit, mark, mark) +// +// return 1 +// +//error: +// STACK_DEL(&context, nodes) +// yaml_free(version_directive_copy) +// while (!STACK_EMPTY(&context, tag_directives_copy)) { +// value yaml_tag_directive_t = POP(&context, tag_directives_copy) +// yaml_free(value.handle) +// yaml_free(value.prefix) +// } +// STACK_DEL(&context, tag_directives_copy) +// yaml_free(value.handle) +// yaml_free(value.prefix) +// +// return 0 +//} +// +///* +// * Destroy a document object. +// */ +// +//YAML_DECLARE(void) +//yaml_document_delete(document *yaml_document_t) +//{ +// struct { +// error yaml_error_type_t +// } context +// tag_directive *yaml_tag_directive_t +// +// context.error = YAML_NO_ERROR // Eliminate a compiler warning. +// +// assert(document) // Non-NULL document object is expected. +// +// while (!STACK_EMPTY(&context, document.nodes)) { +// node yaml_node_t = POP(&context, document.nodes) +// yaml_free(node.tag) +// switch (node.type) { +// case YAML_SCALAR_NODE: +// yaml_free(node.data.scalar.value) +// break +// case YAML_SEQUENCE_NODE: +// STACK_DEL(&context, node.data.sequence.items) +// break +// case YAML_MAPPING_NODE: +// STACK_DEL(&context, node.data.mapping.pairs) +// break +// default: +// assert(0) // Should not happen. +// } +// } +// STACK_DEL(&context, document.nodes) +// +// yaml_free(document.version_directive) +// for (tag_directive = document.tag_directives.start +// tag_directive != document.tag_directives.end +// tag_directive++) { +// yaml_free(tag_directive.handle) +// yaml_free(tag_directive.prefix) +// } +// yaml_free(document.tag_directives.start) +// +// memset(document, 0, sizeof(yaml_document_t)) +//} +// +///** +// * Get a document node. +// */ +// +//YAML_DECLARE(yaml_node_t *) +//yaml_document_get_node(document *yaml_document_t, index int) +//{ +// assert(document) // Non-NULL document object is expected. +// +// if (index > 0 && document.nodes.start + index <= document.nodes.top) { +// return document.nodes.start + index - 1 +// } +// return NULL +//} +// +///** +// * Get the root object. +// */ +// +//YAML_DECLARE(yaml_node_t *) +//yaml_document_get_root_node(document *yaml_document_t) +//{ +// assert(document) // Non-NULL document object is expected. +// +// if (document.nodes.top != document.nodes.start) { +// return document.nodes.start +// } +// return NULL +//} +// +///* +// * Add a scalar node to a document. +// */ +// +//YAML_DECLARE(int) +//yaml_document_add_scalar(document *yaml_document_t, +// tag *yaml_char_t, value *yaml_char_t, length int, +// style yaml_scalar_style_t) +//{ +// struct { +// error yaml_error_type_t +// } context +// mark yaml_mark_t = { 0, 0, 0 } +// tag_copy *yaml_char_t = NULL +// value_copy *yaml_char_t = NULL +// node yaml_node_t +// +// assert(document) // Non-NULL document object is expected. +// assert(value) // Non-NULL value is expected. +// +// if (!tag) { +// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG +// } +// +// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error +// tag_copy = yaml_strdup(tag) +// if (!tag_copy) goto error +// +// if (length < 0) { +// length = strlen((char *)value) +// } +// +// if (!yaml_check_utf8(value, length)) goto error +// value_copy = yaml_malloc(length+1) +// if (!value_copy) goto error +// memcpy(value_copy, value, length) +// value_copy[length] = '\0' +// +// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark) +// if (!PUSH(&context, document.nodes, node)) goto error +// +// return document.nodes.top - document.nodes.start +// +//error: +// yaml_free(tag_copy) +// yaml_free(value_copy) +// +// return 0 +//} +// +///* +// * Add a sequence node to a document. +// */ +// +//YAML_DECLARE(int) +//yaml_document_add_sequence(document *yaml_document_t, +// tag *yaml_char_t, style yaml_sequence_style_t) +//{ +// struct { +// error yaml_error_type_t +// } context +// mark yaml_mark_t = { 0, 0, 0 } +// tag_copy *yaml_char_t = NULL +// struct { +// start *yaml_node_item_t +// end *yaml_node_item_t +// top *yaml_node_item_t +// } items = { NULL, NULL, NULL } +// node yaml_node_t +// +// assert(document) // Non-NULL document object is expected. +// +// if (!tag) { +// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG +// } +// +// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error +// tag_copy = yaml_strdup(tag) +// if (!tag_copy) goto error +// +// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error +// +// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, +// style, mark, mark) +// if (!PUSH(&context, document.nodes, node)) goto error +// +// return document.nodes.top - document.nodes.start +// +//error: +// STACK_DEL(&context, items) +// yaml_free(tag_copy) +// +// return 0 +//} +// +///* +// * Add a mapping node to a document. +// */ +// +//YAML_DECLARE(int) +//yaml_document_add_mapping(document *yaml_document_t, +// tag *yaml_char_t, style yaml_mapping_style_t) +//{ +// struct { +// error yaml_error_type_t +// } context +// mark yaml_mark_t = { 0, 0, 0 } +// tag_copy *yaml_char_t = NULL +// struct { +// start *yaml_node_pair_t +// end *yaml_node_pair_t +// top *yaml_node_pair_t +// } pairs = { NULL, NULL, NULL } +// node yaml_node_t +// +// assert(document) // Non-NULL document object is expected. +// +// if (!tag) { +// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG +// } +// +// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error +// tag_copy = yaml_strdup(tag) +// if (!tag_copy) goto error +// +// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error +// +// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, +// style, mark, mark) +// if (!PUSH(&context, document.nodes, node)) goto error +// +// return document.nodes.top - document.nodes.start +// +//error: +// STACK_DEL(&context, pairs) +// yaml_free(tag_copy) +// +// return 0 +//} +// +///* +// * Append an item to a sequence node. +// */ +// +//YAML_DECLARE(int) +//yaml_document_append_sequence_item(document *yaml_document_t, +// sequence int, item int) +//{ +// struct { +// error yaml_error_type_t +// } context +// +// assert(document) // Non-NULL document is required. +// assert(sequence > 0 +// && document.nodes.start + sequence <= document.nodes.top) +// // Valid sequence id is required. +// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE) +// // A sequence node is required. +// assert(item > 0 && document.nodes.start + item <= document.nodes.top) +// // Valid item id is required. +// +// if (!PUSH(&context, +// document.nodes.start[sequence-1].data.sequence.items, item)) +// return 0 +// +// return 1 +//} +// +///* +// * Append a pair of a key and a value to a mapping node. +// */ +// +//YAML_DECLARE(int) +//yaml_document_append_mapping_pair(document *yaml_document_t, +// mapping int, key int, value int) +//{ +// struct { +// error yaml_error_type_t +// } context +// +// pair yaml_node_pair_t +// +// assert(document) // Non-NULL document is required. +// assert(mapping > 0 +// && document.nodes.start + mapping <= document.nodes.top) +// // Valid mapping id is required. +// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE) +// // A mapping node is required. +// assert(key > 0 && document.nodes.start + key <= document.nodes.top) +// // Valid key id is required. +// assert(value > 0 && document.nodes.start + value <= document.nodes.top) +// // Valid value id is required. +// +// pair.key = key +// pair.value = value +// +// if (!PUSH(&context, +// document.nodes.start[mapping-1].data.mapping.pairs, pair)) +// return 0 +// +// return 1 +//} +// +// diff --git a/vendor/gopkg.in/yaml.v2/decode.go b/vendor/gopkg.in/yaml.v2/decode.go new file mode 100644 index 0000000..129bc2a --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/decode.go @@ -0,0 +1,815 @@ +package yaml + +import ( + "encoding" + "encoding/base64" + "fmt" + "io" + "math" + "reflect" + "strconv" + "time" +) + +const ( + documentNode = 1 << iota + mappingNode + sequenceNode + scalarNode + aliasNode +) + +type node struct { + kind int + line, column int + tag string + // For an alias node, alias holds the resolved alias. + alias *node + value string + implicit bool + children []*node + anchors map[string]*node +} + +// ---------------------------------------------------------------------------- +// Parser, produces a node tree out of a libyaml event stream. + +type parser struct { + parser yaml_parser_t + event yaml_event_t + doc *node + doneInit bool +} + +func newParser(b []byte) *parser { + p := parser{} + if !yaml_parser_initialize(&p.parser) { + panic("failed to initialize YAML emitter") + } + if len(b) == 0 { + b = []byte{'\n'} + } + yaml_parser_set_input_string(&p.parser, b) + return &p +} + +func newParserFromReader(r io.Reader) *parser { + p := parser{} + if !yaml_parser_initialize(&p.parser) { + panic("failed to initialize YAML emitter") + } + yaml_parser_set_input_reader(&p.parser, r) + return &p +} + +func (p *parser) init() { + if p.doneInit { + return + } + p.expect(yaml_STREAM_START_EVENT) + p.doneInit = true +} + +func (p *parser) destroy() { + if p.event.typ != yaml_NO_EVENT { + yaml_event_delete(&p.event) + } + yaml_parser_delete(&p.parser) +} + +// expect consumes an event from the event stream and +// checks that it's of the expected type. +func (p *parser) expect(e yaml_event_type_t) { + if p.event.typ == yaml_NO_EVENT { + if !yaml_parser_parse(&p.parser, &p.event) { + p.fail() + } + } + if p.event.typ == yaml_STREAM_END_EVENT { + failf("attempted to go past the end of stream; corrupted value?") + } + if p.event.typ != e { + p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ) + p.fail() + } + yaml_event_delete(&p.event) + p.event.typ = yaml_NO_EVENT +} + +// peek peeks at the next event in the event stream, +// puts the results into p.event and returns the event type. +func (p *parser) peek() yaml_event_type_t { + if p.event.typ != yaml_NO_EVENT { + return p.event.typ + } + if !yaml_parser_parse(&p.parser, &p.event) { + p.fail() + } + return p.event.typ +} + +func (p *parser) fail() { + var where string + var line int + if p.parser.problem_mark.line != 0 { + line = p.parser.problem_mark.line + // Scanner errors don't iterate line before returning error + if p.parser.error == yaml_SCANNER_ERROR { + line++ + } + } else if p.parser.context_mark.line != 0 { + line = p.parser.context_mark.line + } + if line != 0 { + where = "line " + strconv.Itoa(line) + ": " + } + var msg string + if len(p.parser.problem) > 0 { + msg = p.parser.problem + } else { + msg = "unknown problem parsing YAML content" + } + failf("%s%s", where, msg) +} + +func (p *parser) anchor(n *node, anchor []byte) { + if anchor != nil { + p.doc.anchors[string(anchor)] = n + } +} + +func (p *parser) parse() *node { + p.init() + switch p.peek() { + case yaml_SCALAR_EVENT: + return p.scalar() + case yaml_ALIAS_EVENT: + return p.alias() + case yaml_MAPPING_START_EVENT: + return p.mapping() + case yaml_SEQUENCE_START_EVENT: + return p.sequence() + case yaml_DOCUMENT_START_EVENT: + return p.document() + case yaml_STREAM_END_EVENT: + // Happens when attempting to decode an empty buffer. + return nil + default: + panic("attempted to parse unknown event: " + p.event.typ.String()) + } +} + +func (p *parser) node(kind int) *node { + return &node{ + kind: kind, + line: p.event.start_mark.line, + column: p.event.start_mark.column, + } +} + +func (p *parser) document() *node { + n := p.node(documentNode) + n.anchors = make(map[string]*node) + p.doc = n + p.expect(yaml_DOCUMENT_START_EVENT) + n.children = append(n.children, p.parse()) + p.expect(yaml_DOCUMENT_END_EVENT) + return n +} + +func (p *parser) alias() *node { + n := p.node(aliasNode) + n.value = string(p.event.anchor) + n.alias = p.doc.anchors[n.value] + if n.alias == nil { + failf("unknown anchor '%s' referenced", n.value) + } + p.expect(yaml_ALIAS_EVENT) + return n +} + +func (p *parser) scalar() *node { + n := p.node(scalarNode) + n.value = string(p.event.value) + n.tag = string(p.event.tag) + n.implicit = p.event.implicit + p.anchor(n, p.event.anchor) + p.expect(yaml_SCALAR_EVENT) + return n +} + +func (p *parser) sequence() *node { + n := p.node(sequenceNode) + p.anchor(n, p.event.anchor) + p.expect(yaml_SEQUENCE_START_EVENT) + for p.peek() != yaml_SEQUENCE_END_EVENT { + n.children = append(n.children, p.parse()) + } + p.expect(yaml_SEQUENCE_END_EVENT) + return n +} + +func (p *parser) mapping() *node { + n := p.node(mappingNode) + p.anchor(n, p.event.anchor) + p.expect(yaml_MAPPING_START_EVENT) + for p.peek() != yaml_MAPPING_END_EVENT { + n.children = append(n.children, p.parse(), p.parse()) + } + p.expect(yaml_MAPPING_END_EVENT) + return n +} + +// ---------------------------------------------------------------------------- +// Decoder, unmarshals a node into a provided value. + +type decoder struct { + doc *node + aliases map[*node]bool + mapType reflect.Type + terrors []string + strict bool + + decodeCount int + aliasCount int + aliasDepth int +} + +var ( + mapItemType = reflect.TypeOf(MapItem{}) + durationType = reflect.TypeOf(time.Duration(0)) + defaultMapType = reflect.TypeOf(map[interface{}]interface{}{}) + ifaceType = defaultMapType.Elem() + timeType = reflect.TypeOf(time.Time{}) + ptrTimeType = reflect.TypeOf(&time.Time{}) +) + +func newDecoder(strict bool) *decoder { + d := &decoder{mapType: defaultMapType, strict: strict} + d.aliases = make(map[*node]bool) + return d +} + +func (d *decoder) terror(n *node, tag string, out reflect.Value) { + if n.tag != "" { + tag = n.tag + } + value := n.value + if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG { + if len(value) > 10 { + value = " `" + value[:7] + "...`" + } else { + value = " `" + value + "`" + } + } + d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type())) +} + +func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) { + terrlen := len(d.terrors) + err := u.UnmarshalYAML(func(v interface{}) (err error) { + defer handleErr(&err) + d.unmarshal(n, reflect.ValueOf(v)) + if len(d.terrors) > terrlen { + issues := d.terrors[terrlen:] + d.terrors = d.terrors[:terrlen] + return &TypeError{issues} + } + return nil + }) + if e, ok := err.(*TypeError); ok { + d.terrors = append(d.terrors, e.Errors...) + return false + } + if err != nil { + fail(err) + } + return true +} + +// d.prepare initializes and dereferences pointers and calls UnmarshalYAML +// if a value is found to implement it. +// It returns the initialized and dereferenced out value, whether +// unmarshalling was already done by UnmarshalYAML, and if so whether +// its types unmarshalled appropriately. +// +// If n holds a null value, prepare returns before doing anything. +func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) { + if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) { + return out, false, false + } + again := true + for again { + again = false + if out.Kind() == reflect.Ptr { + if out.IsNil() { + out.Set(reflect.New(out.Type().Elem())) + } + out = out.Elem() + again = true + } + if out.CanAddr() { + if u, ok := out.Addr().Interface().(Unmarshaler); ok { + good = d.callUnmarshaler(n, u) + return out, true, good + } + } + } + return out, false, false +} + +const ( + // 400,000 decode operations is ~500kb of dense object declarations, or + // ~5kb of dense object declarations with 10000% alias expansion + alias_ratio_range_low = 400000 + + // 4,000,000 decode operations is ~5MB of dense object declarations, or + // ~4.5MB of dense object declarations with 10% alias expansion + alias_ratio_range_high = 4000000 + + // alias_ratio_range is the range over which we scale allowed alias ratios + alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low) +) + +func allowedAliasRatio(decodeCount int) float64 { + switch { + case decodeCount <= alias_ratio_range_low: + // allow 99% to come from alias expansion for small-to-medium documents + return 0.99 + case decodeCount >= alias_ratio_range_high: + // allow 10% to come from alias expansion for very large documents + return 0.10 + default: + // scale smoothly from 99% down to 10% over the range. + // this maps to 396,000 - 400,000 allowed alias-driven decodes over the range. + // 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps). + return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range) + } +} + +func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) { + d.decodeCount++ + if d.aliasDepth > 0 { + d.aliasCount++ + } + if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) { + failf("document contains excessive aliasing") + } + switch n.kind { + case documentNode: + return d.document(n, out) + case aliasNode: + return d.alias(n, out) + } + out, unmarshaled, good := d.prepare(n, out) + if unmarshaled { + return good + } + switch n.kind { + case scalarNode: + good = d.scalar(n, out) + case mappingNode: + good = d.mapping(n, out) + case sequenceNode: + good = d.sequence(n, out) + default: + panic("internal error: unknown node kind: " + strconv.Itoa(n.kind)) + } + return good +} + +func (d *decoder) document(n *node, out reflect.Value) (good bool) { + if len(n.children) == 1 { + d.doc = n + d.unmarshal(n.children[0], out) + return true + } + return false +} + +func (d *decoder) alias(n *node, out reflect.Value) (good bool) { + if d.aliases[n] { + // TODO this could actually be allowed in some circumstances. + failf("anchor '%s' value contains itself", n.value) + } + d.aliases[n] = true + d.aliasDepth++ + good = d.unmarshal(n.alias, out) + d.aliasDepth-- + delete(d.aliases, n) + return good +} + +var zeroValue reflect.Value + +func resetMap(out reflect.Value) { + for _, k := range out.MapKeys() { + out.SetMapIndex(k, zeroValue) + } +} + +func (d *decoder) scalar(n *node, out reflect.Value) bool { + var tag string + var resolved interface{} + if n.tag == "" && !n.implicit { + tag = yaml_STR_TAG + resolved = n.value + } else { + tag, resolved = resolve(n.tag, n.value) + if tag == yaml_BINARY_TAG { + data, err := base64.StdEncoding.DecodeString(resolved.(string)) + if err != nil { + failf("!!binary value contains invalid base64 data") + } + resolved = string(data) + } + } + if resolved == nil { + if out.Kind() == reflect.Map && !out.CanAddr() { + resetMap(out) + } else { + out.Set(reflect.Zero(out.Type())) + } + return true + } + if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { + // We've resolved to exactly the type we want, so use that. + out.Set(resolvedv) + return true + } + // Perhaps we can use the value as a TextUnmarshaler to + // set its value. + if out.CanAddr() { + u, ok := out.Addr().Interface().(encoding.TextUnmarshaler) + if ok { + var text []byte + if tag == yaml_BINARY_TAG { + text = []byte(resolved.(string)) + } else { + // We let any value be unmarshaled into TextUnmarshaler. + // That might be more lax than we'd like, but the + // TextUnmarshaler itself should bowl out any dubious values. + text = []byte(n.value) + } + err := u.UnmarshalText(text) + if err != nil { + fail(err) + } + return true + } + } + switch out.Kind() { + case reflect.String: + if tag == yaml_BINARY_TAG { + out.SetString(resolved.(string)) + return true + } + if resolved != nil { + out.SetString(n.value) + return true + } + case reflect.Interface: + if resolved == nil { + out.Set(reflect.Zero(out.Type())) + } else if tag == yaml_TIMESTAMP_TAG { + // It looks like a timestamp but for backward compatibility + // reasons we set it as a string, so that code that unmarshals + // timestamp-like values into interface{} will continue to + // see a string and not a time.Time. + // TODO(v3) Drop this. + out.Set(reflect.ValueOf(n.value)) + } else { + out.Set(reflect.ValueOf(resolved)) + } + return true + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch resolved := resolved.(type) { + case int: + if !out.OverflowInt(int64(resolved)) { + out.SetInt(int64(resolved)) + return true + } + case int64: + if !out.OverflowInt(resolved) { + out.SetInt(resolved) + return true + } + case uint64: + if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { + out.SetInt(int64(resolved)) + return true + } + case float64: + if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { + out.SetInt(int64(resolved)) + return true + } + case string: + if out.Type() == durationType { + d, err := time.ParseDuration(resolved) + if err == nil { + out.SetInt(int64(d)) + return true + } + } + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + switch resolved := resolved.(type) { + case int: + if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { + out.SetUint(uint64(resolved)) + return true + } + case int64: + if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { + out.SetUint(uint64(resolved)) + return true + } + case uint64: + if !out.OverflowUint(uint64(resolved)) { + out.SetUint(uint64(resolved)) + return true + } + case float64: + if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) { + out.SetUint(uint64(resolved)) + return true + } + } + case reflect.Bool: + switch resolved := resolved.(type) { + case bool: + out.SetBool(resolved) + return true + } + case reflect.Float32, reflect.Float64: + switch resolved := resolved.(type) { + case int: + out.SetFloat(float64(resolved)) + return true + case int64: + out.SetFloat(float64(resolved)) + return true + case uint64: + out.SetFloat(float64(resolved)) + return true + case float64: + out.SetFloat(resolved) + return true + } + case reflect.Struct: + if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { + out.Set(resolvedv) + return true + } + case reflect.Ptr: + if out.Type().Elem() == reflect.TypeOf(resolved) { + // TODO DOes this make sense? When is out a Ptr except when decoding a nil value? + elem := reflect.New(out.Type().Elem()) + elem.Elem().Set(reflect.ValueOf(resolved)) + out.Set(elem) + return true + } + } + d.terror(n, tag, out) + return false +} + +func settableValueOf(i interface{}) reflect.Value { + v := reflect.ValueOf(i) + sv := reflect.New(v.Type()).Elem() + sv.Set(v) + return sv +} + +func (d *decoder) sequence(n *node, out reflect.Value) (good bool) { + l := len(n.children) + + var iface reflect.Value + switch out.Kind() { + case reflect.Slice: + out.Set(reflect.MakeSlice(out.Type(), l, l)) + case reflect.Array: + if l != out.Len() { + failf("invalid array: want %d elements but got %d", out.Len(), l) + } + case reflect.Interface: + // No type hints. Will have to use a generic sequence. + iface = out + out = settableValueOf(make([]interface{}, l)) + default: + d.terror(n, yaml_SEQ_TAG, out) + return false + } + et := out.Type().Elem() + + j := 0 + for i := 0; i < l; i++ { + e := reflect.New(et).Elem() + if ok := d.unmarshal(n.children[i], e); ok { + out.Index(j).Set(e) + j++ + } + } + if out.Kind() != reflect.Array { + out.Set(out.Slice(0, j)) + } + if iface.IsValid() { + iface.Set(out) + } + return true +} + +func (d *decoder) mapping(n *node, out reflect.Value) (good bool) { + switch out.Kind() { + case reflect.Struct: + return d.mappingStruct(n, out) + case reflect.Slice: + return d.mappingSlice(n, out) + case reflect.Map: + // okay + case reflect.Interface: + if d.mapType.Kind() == reflect.Map { + iface := out + out = reflect.MakeMap(d.mapType) + iface.Set(out) + } else { + slicev := reflect.New(d.mapType).Elem() + if !d.mappingSlice(n, slicev) { + return false + } + out.Set(slicev) + return true + } + default: + d.terror(n, yaml_MAP_TAG, out) + return false + } + outt := out.Type() + kt := outt.Key() + et := outt.Elem() + + mapType := d.mapType + if outt.Key() == ifaceType && outt.Elem() == ifaceType { + d.mapType = outt + } + + if out.IsNil() { + out.Set(reflect.MakeMap(outt)) + } + l := len(n.children) + for i := 0; i < l; i += 2 { + if isMerge(n.children[i]) { + d.merge(n.children[i+1], out) + continue + } + k := reflect.New(kt).Elem() + if d.unmarshal(n.children[i], k) { + kkind := k.Kind() + if kkind == reflect.Interface { + kkind = k.Elem().Kind() + } + if kkind == reflect.Map || kkind == reflect.Slice { + failf("invalid map key: %#v", k.Interface()) + } + e := reflect.New(et).Elem() + if d.unmarshal(n.children[i+1], e) { + d.setMapIndex(n.children[i+1], out, k, e) + } + } + } + d.mapType = mapType + return true +} + +func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) { + if d.strict && out.MapIndex(k) != zeroValue { + d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface())) + return + } + out.SetMapIndex(k, v) +} + +func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) { + outt := out.Type() + if outt.Elem() != mapItemType { + d.terror(n, yaml_MAP_TAG, out) + return false + } + + mapType := d.mapType + d.mapType = outt + + var slice []MapItem + var l = len(n.children) + for i := 0; i < l; i += 2 { + if isMerge(n.children[i]) { + d.merge(n.children[i+1], out) + continue + } + item := MapItem{} + k := reflect.ValueOf(&item.Key).Elem() + if d.unmarshal(n.children[i], k) { + v := reflect.ValueOf(&item.Value).Elem() + if d.unmarshal(n.children[i+1], v) { + slice = append(slice, item) + } + } + } + out.Set(reflect.ValueOf(slice)) + d.mapType = mapType + return true +} + +func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) { + sinfo, err := getStructInfo(out.Type()) + if err != nil { + panic(err) + } + name := settableValueOf("") + l := len(n.children) + + var inlineMap reflect.Value + var elemType reflect.Type + if sinfo.InlineMap != -1 { + inlineMap = out.Field(sinfo.InlineMap) + inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) + elemType = inlineMap.Type().Elem() + } + + var doneFields []bool + if d.strict { + doneFields = make([]bool, len(sinfo.FieldsList)) + } + for i := 0; i < l; i += 2 { + ni := n.children[i] + if isMerge(ni) { + d.merge(n.children[i+1], out) + continue + } + if !d.unmarshal(ni, name) { + continue + } + if info, ok := sinfo.FieldsMap[name.String()]; ok { + if d.strict { + if doneFields[info.Id] { + d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type())) + continue + } + doneFields[info.Id] = true + } + var field reflect.Value + if info.Inline == nil { + field = out.Field(info.Num) + } else { + field = out.FieldByIndex(info.Inline) + } + d.unmarshal(n.children[i+1], field) + } else if sinfo.InlineMap != -1 { + if inlineMap.IsNil() { + inlineMap.Set(reflect.MakeMap(inlineMap.Type())) + } + value := reflect.New(elemType).Elem() + d.unmarshal(n.children[i+1], value) + d.setMapIndex(n.children[i+1], inlineMap, name, value) + } else if d.strict { + d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type())) + } + } + return true +} + +func failWantMap() { + failf("map merge requires map or sequence of maps as the value") +} + +func (d *decoder) merge(n *node, out reflect.Value) { + switch n.kind { + case mappingNode: + d.unmarshal(n, out) + case aliasNode: + if n.alias != nil && n.alias.kind != mappingNode { + failWantMap() + } + d.unmarshal(n, out) + case sequenceNode: + // Step backwards as earlier nodes take precedence. + for i := len(n.children) - 1; i >= 0; i-- { + ni := n.children[i] + if ni.kind == aliasNode { + if ni.alias != nil && ni.alias.kind != mappingNode { + failWantMap() + } + } else if ni.kind != mappingNode { + failWantMap() + } + d.unmarshal(ni, out) + } + default: + failWantMap() + } +} + +func isMerge(n *node) bool { + return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG) +} diff --git a/vendor/gopkg.in/yaml.v2/emitterc.go b/vendor/gopkg.in/yaml.v2/emitterc.go new file mode 100644 index 0000000..a1c2cc5 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/emitterc.go @@ -0,0 +1,1685 @@ +package yaml + +import ( + "bytes" + "fmt" +) + +// Flush the buffer if needed. +func flush(emitter *yaml_emitter_t) bool { + if emitter.buffer_pos+5 >= len(emitter.buffer) { + return yaml_emitter_flush(emitter) + } + return true +} + +// Put a character to the output buffer. +func put(emitter *yaml_emitter_t, value byte) bool { + if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { + return false + } + emitter.buffer[emitter.buffer_pos] = value + emitter.buffer_pos++ + emitter.column++ + return true +} + +// Put a line break to the output buffer. +func put_break(emitter *yaml_emitter_t) bool { + if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { + return false + } + switch emitter.line_break { + case yaml_CR_BREAK: + emitter.buffer[emitter.buffer_pos] = '\r' + emitter.buffer_pos += 1 + case yaml_LN_BREAK: + emitter.buffer[emitter.buffer_pos] = '\n' + emitter.buffer_pos += 1 + case yaml_CRLN_BREAK: + emitter.buffer[emitter.buffer_pos+0] = '\r' + emitter.buffer[emitter.buffer_pos+1] = '\n' + emitter.buffer_pos += 2 + default: + panic("unknown line break setting") + } + emitter.column = 0 + emitter.line++ + return true +} + +// Copy a character from a string into buffer. +func write(emitter *yaml_emitter_t, s []byte, i *int) bool { + if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { + return false + } + p := emitter.buffer_pos + w := width(s[*i]) + switch w { + case 4: + emitter.buffer[p+3] = s[*i+3] + fallthrough + case 3: + emitter.buffer[p+2] = s[*i+2] + fallthrough + case 2: + emitter.buffer[p+1] = s[*i+1] + fallthrough + case 1: + emitter.buffer[p+0] = s[*i+0] + default: + panic("unknown character width") + } + emitter.column++ + emitter.buffer_pos += w + *i += w + return true +} + +// Write a whole string into buffer. +func write_all(emitter *yaml_emitter_t, s []byte) bool { + for i := 0; i < len(s); { + if !write(emitter, s, &i) { + return false + } + } + return true +} + +// Copy a line break character from a string into buffer. +func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool { + if s[*i] == '\n' { + if !put_break(emitter) { + return false + } + *i++ + } else { + if !write(emitter, s, i) { + return false + } + emitter.column = 0 + emitter.line++ + } + return true +} + +// Set an emitter error and return false. +func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool { + emitter.error = yaml_EMITTER_ERROR + emitter.problem = problem + return false +} + +// Emit an event. +func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool { + emitter.events = append(emitter.events, *event) + for !yaml_emitter_need_more_events(emitter) { + event := &emitter.events[emitter.events_head] + if !yaml_emitter_analyze_event(emitter, event) { + return false + } + if !yaml_emitter_state_machine(emitter, event) { + return false + } + yaml_event_delete(event) + emitter.events_head++ + } + return true +} + +// Check if we need to accumulate more events before emitting. +// +// We accumulate extra +// - 1 event for DOCUMENT-START +// - 2 events for SEQUENCE-START +// - 3 events for MAPPING-START +// +func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool { + if emitter.events_head == len(emitter.events) { + return true + } + var accumulate int + switch emitter.events[emitter.events_head].typ { + case yaml_DOCUMENT_START_EVENT: + accumulate = 1 + break + case yaml_SEQUENCE_START_EVENT: + accumulate = 2 + break + case yaml_MAPPING_START_EVENT: + accumulate = 3 + break + default: + return false + } + if len(emitter.events)-emitter.events_head > accumulate { + return false + } + var level int + for i := emitter.events_head; i < len(emitter.events); i++ { + switch emitter.events[i].typ { + case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT: + level++ + case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT: + level-- + } + if level == 0 { + return false + } + } + return true +} + +// Append a directive to the directives stack. +func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool { + for i := 0; i < len(emitter.tag_directives); i++ { + if bytes.Equal(value.handle, emitter.tag_directives[i].handle) { + if allow_duplicates { + return true + } + return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive") + } + } + + // [Go] Do we actually need to copy this given garbage collection + // and the lack of deallocating destructors? + tag_copy := yaml_tag_directive_t{ + handle: make([]byte, len(value.handle)), + prefix: make([]byte, len(value.prefix)), + } + copy(tag_copy.handle, value.handle) + copy(tag_copy.prefix, value.prefix) + emitter.tag_directives = append(emitter.tag_directives, tag_copy) + return true +} + +// Increase the indentation level. +func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool { + emitter.indents = append(emitter.indents, emitter.indent) + if emitter.indent < 0 { + if flow { + emitter.indent = emitter.best_indent + } else { + emitter.indent = 0 + } + } else if !indentless { + emitter.indent += emitter.best_indent + } + return true +} + +// State dispatcher. +func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool { + switch emitter.state { + default: + case yaml_EMIT_STREAM_START_STATE: + return yaml_emitter_emit_stream_start(emitter, event) + + case yaml_EMIT_FIRST_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, true) + + case yaml_EMIT_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, false) + + case yaml_EMIT_DOCUMENT_CONTENT_STATE: + return yaml_emitter_emit_document_content(emitter, event) + + case yaml_EMIT_DOCUMENT_END_STATE: + return yaml_emitter_emit_document_end(emitter, event) + + case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, true) + + case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, false) + + case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, true) + + case yaml_EMIT_FLOW_MAPPING_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, false) + + case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, true) + + case yaml_EMIT_FLOW_MAPPING_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, false) + + case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, true) + + case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, false) + + case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, true) + + case yaml_EMIT_BLOCK_MAPPING_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, false) + + case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, true) + + case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, false) + + case yaml_EMIT_END_STATE: + return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END") + } + panic("invalid emitter state") +} + +// Expect STREAM-START. +func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if event.typ != yaml_STREAM_START_EVENT { + return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START") + } + if emitter.encoding == yaml_ANY_ENCODING { + emitter.encoding = event.encoding + if emitter.encoding == yaml_ANY_ENCODING { + emitter.encoding = yaml_UTF8_ENCODING + } + } + if emitter.best_indent < 2 || emitter.best_indent > 9 { + emitter.best_indent = 2 + } + if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 { + emitter.best_width = 80 + } + if emitter.best_width < 0 { + emitter.best_width = 1<<31 - 1 + } + if emitter.line_break == yaml_ANY_BREAK { + emitter.line_break = yaml_LN_BREAK + } + + emitter.indent = -1 + emitter.line = 0 + emitter.column = 0 + emitter.whitespace = true + emitter.indention = true + + if emitter.encoding != yaml_UTF8_ENCODING { + if !yaml_emitter_write_bom(emitter) { + return false + } + } + emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE + return true +} + +// Expect DOCUMENT-START or STREAM-END. +func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { + + if event.typ == yaml_DOCUMENT_START_EVENT { + + if event.version_directive != nil { + if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) { + return false + } + } + + for i := 0; i < len(event.tag_directives); i++ { + tag_directive := &event.tag_directives[i] + if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) { + return false + } + if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) { + return false + } + } + + for i := 0; i < len(default_tag_directives); i++ { + tag_directive := &default_tag_directives[i] + if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) { + return false + } + } + + implicit := event.implicit + if !first || emitter.canonical { + implicit = false + } + + if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) { + if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if event.version_directive != nil { + implicit = false + if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if len(event.tag_directives) > 0 { + implicit = false + for i := 0; i < len(event.tag_directives); i++ { + tag_directive := &event.tag_directives[i] + if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) { + return false + } + if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) { + return false + } + if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + } + + if yaml_emitter_check_empty_document(emitter) { + implicit = false + } + if !implicit { + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) { + return false + } + if emitter.canonical { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + } + + emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE + return true + } + + if event.typ == yaml_STREAM_END_EVENT { + if emitter.open_ended { + if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_flush(emitter) { + return false + } + emitter.state = yaml_EMIT_END_STATE + return true + } + + return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END") +} + +// Expect the root node. +func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool { + emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE) + return yaml_emitter_emit_node(emitter, event, true, false, false, false) +} + +// Expect DOCUMENT-END. +func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if event.typ != yaml_DOCUMENT_END_EVENT { + return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END") + } + if !yaml_emitter_write_indent(emitter) { + return false + } + if !event.implicit { + // [Go] Allocate the slice elsewhere. + if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_flush(emitter) { + return false + } + emitter.state = yaml_EMIT_DOCUMENT_START_STATE + emitter.tag_directives = emitter.tag_directives[:0] + return true +} + +// Expect a flow item node. +func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { + if first { + if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) { + return false + } + if !yaml_emitter_increase_indent(emitter, true, false) { + return false + } + emitter.flow_level++ + } + + if event.typ == yaml_SEQUENCE_END_EVENT { + emitter.flow_level-- + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + if emitter.canonical && !first { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) { + return false + } + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + + return true + } + + if !first { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + + if emitter.canonical || emitter.column > emitter.best_width { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE) + return yaml_emitter_emit_node(emitter, event, false, true, false, false) +} + +// Expect a flow key node. +func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { + if first { + if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) { + return false + } + if !yaml_emitter_increase_indent(emitter, true, false) { + return false + } + emitter.flow_level++ + } + + if event.typ == yaml_MAPPING_END_EVENT { + emitter.flow_level-- + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + if emitter.canonical && !first { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) { + return false + } + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true + } + + if !first { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + if emitter.canonical || emitter.column > emitter.best_width { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if !emitter.canonical && yaml_emitter_check_simple_key(emitter) { + emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, true) + } + if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) { + return false + } + emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, false) +} + +// Expect a flow value node. +func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { + if simple { + if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { + return false + } + } else { + if emitter.canonical || emitter.column > emitter.best_width { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) { + return false + } + } + emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, false) +} + +// Expect a block item node. +func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { + if first { + if !yaml_emitter_increase_indent(emitter, false, emitter.mapping_context && !emitter.indention) { + return false + } + } + if event.typ == yaml_SEQUENCE_END_EVENT { + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true + } + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) { + return false + } + emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE) + return yaml_emitter_emit_node(emitter, event, false, true, false, false) +} + +// Expect a block key node. +func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { + if first { + if !yaml_emitter_increase_indent(emitter, false, false) { + return false + } + } + if event.typ == yaml_MAPPING_END_EVENT { + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true + } + if !yaml_emitter_write_indent(emitter) { + return false + } + if yaml_emitter_check_simple_key(emitter) { + emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, true) + } + if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) { + return false + } + emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, false) +} + +// Expect a block value node. +func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { + if simple { + if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { + return false + } + } else { + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) { + return false + } + } + emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, false) +} + +// Expect a node. +func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t, + root bool, sequence bool, mapping bool, simple_key bool) bool { + + emitter.root_context = root + emitter.sequence_context = sequence + emitter.mapping_context = mapping + emitter.simple_key_context = simple_key + + switch event.typ { + case yaml_ALIAS_EVENT: + return yaml_emitter_emit_alias(emitter, event) + case yaml_SCALAR_EVENT: + return yaml_emitter_emit_scalar(emitter, event) + case yaml_SEQUENCE_START_EVENT: + return yaml_emitter_emit_sequence_start(emitter, event) + case yaml_MAPPING_START_EVENT: + return yaml_emitter_emit_mapping_start(emitter, event) + default: + return yaml_emitter_set_emitter_error(emitter, + fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ)) + } +} + +// Expect ALIAS. +func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if !yaml_emitter_process_anchor(emitter) { + return false + } + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true +} + +// Expect SCALAR. +func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if !yaml_emitter_select_scalar_style(emitter, event) { + return false + } + if !yaml_emitter_process_anchor(emitter) { + return false + } + if !yaml_emitter_process_tag(emitter) { + return false + } + if !yaml_emitter_increase_indent(emitter, true, false) { + return false + } + if !yaml_emitter_process_scalar(emitter) { + return false + } + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true +} + +// Expect SEQUENCE-START. +func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if !yaml_emitter_process_anchor(emitter) { + return false + } + if !yaml_emitter_process_tag(emitter) { + return false + } + if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE || + yaml_emitter_check_empty_sequence(emitter) { + emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE + } else { + emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE + } + return true +} + +// Expect MAPPING-START. +func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if !yaml_emitter_process_anchor(emitter) { + return false + } + if !yaml_emitter_process_tag(emitter) { + return false + } + if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE || + yaml_emitter_check_empty_mapping(emitter) { + emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE + } else { + emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE + } + return true +} + +// Check if the document content is an empty scalar. +func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool { + return false // [Go] Huh? +} + +// Check if the next events represent an empty sequence. +func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool { + if len(emitter.events)-emitter.events_head < 2 { + return false + } + return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT && + emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT +} + +// Check if the next events represent an empty mapping. +func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool { + if len(emitter.events)-emitter.events_head < 2 { + return false + } + return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT && + emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT +} + +// Check if the next node can be expressed as a simple key. +func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool { + length := 0 + switch emitter.events[emitter.events_head].typ { + case yaml_ALIAS_EVENT: + length += len(emitter.anchor_data.anchor) + case yaml_SCALAR_EVENT: + if emitter.scalar_data.multiline { + return false + } + length += len(emitter.anchor_data.anchor) + + len(emitter.tag_data.handle) + + len(emitter.tag_data.suffix) + + len(emitter.scalar_data.value) + case yaml_SEQUENCE_START_EVENT: + if !yaml_emitter_check_empty_sequence(emitter) { + return false + } + length += len(emitter.anchor_data.anchor) + + len(emitter.tag_data.handle) + + len(emitter.tag_data.suffix) + case yaml_MAPPING_START_EVENT: + if !yaml_emitter_check_empty_mapping(emitter) { + return false + } + length += len(emitter.anchor_data.anchor) + + len(emitter.tag_data.handle) + + len(emitter.tag_data.suffix) + default: + return false + } + return length <= 128 +} + +// Determine an acceptable scalar style. +func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool { + + no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 + if no_tag && !event.implicit && !event.quoted_implicit { + return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified") + } + + style := event.scalar_style() + if style == yaml_ANY_SCALAR_STYLE { + style = yaml_PLAIN_SCALAR_STYLE + } + if emitter.canonical { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + if emitter.simple_key_context && emitter.scalar_data.multiline { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + + if style == yaml_PLAIN_SCALAR_STYLE { + if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed || + emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed { + style = yaml_SINGLE_QUOTED_SCALAR_STYLE + } + if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) { + style = yaml_SINGLE_QUOTED_SCALAR_STYLE + } + if no_tag && !event.implicit { + style = yaml_SINGLE_QUOTED_SCALAR_STYLE + } + } + if style == yaml_SINGLE_QUOTED_SCALAR_STYLE { + if !emitter.scalar_data.single_quoted_allowed { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + } + if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE { + if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + } + + if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE { + emitter.tag_data.handle = []byte{'!'} + } + emitter.scalar_data.style = style + return true +} + +// Write an anchor. +func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool { + if emitter.anchor_data.anchor == nil { + return true + } + c := []byte{'&'} + if emitter.anchor_data.alias { + c[0] = '*' + } + if !yaml_emitter_write_indicator(emitter, c, true, false, false) { + return false + } + return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor) +} + +// Write a tag. +func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool { + if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 { + return true + } + if len(emitter.tag_data.handle) > 0 { + if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) { + return false + } + if len(emitter.tag_data.suffix) > 0 { + if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { + return false + } + } + } else { + // [Go] Allocate these slices elsewhere. + if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) { + return false + } + if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) { + return false + } + } + return true +} + +// Write a scalar. +func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool { + switch emitter.scalar_data.style { + case yaml_PLAIN_SCALAR_STYLE: + return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) + + case yaml_SINGLE_QUOTED_SCALAR_STYLE: + return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) + + case yaml_DOUBLE_QUOTED_SCALAR_STYLE: + return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) + + case yaml_LITERAL_SCALAR_STYLE: + return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value) + + case yaml_FOLDED_SCALAR_STYLE: + return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value) + } + panic("unknown scalar style") +} + +// Check if a %YAML directive is valid. +func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool { + if version_directive.major != 1 || version_directive.minor != 1 { + return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive") + } + return true +} + +// Check if a %TAG directive is valid. +func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool { + handle := tag_directive.handle + prefix := tag_directive.prefix + if len(handle) == 0 { + return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty") + } + if handle[0] != '!' { + return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'") + } + if handle[len(handle)-1] != '!' { + return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'") + } + for i := 1; i < len(handle)-1; i += width(handle[i]) { + if !is_alpha(handle, i) { + return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only") + } + } + if len(prefix) == 0 { + return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty") + } + return true +} + +// Check if an anchor is valid. +func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool { + if len(anchor) == 0 { + problem := "anchor value must not be empty" + if alias { + problem = "alias value must not be empty" + } + return yaml_emitter_set_emitter_error(emitter, problem) + } + for i := 0; i < len(anchor); i += width(anchor[i]) { + if !is_alpha(anchor, i) { + problem := "anchor value must contain alphanumerical characters only" + if alias { + problem = "alias value must contain alphanumerical characters only" + } + return yaml_emitter_set_emitter_error(emitter, problem) + } + } + emitter.anchor_data.anchor = anchor + emitter.anchor_data.alias = alias + return true +} + +// Check if a tag is valid. +func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool { + if len(tag) == 0 { + return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty") + } + for i := 0; i < len(emitter.tag_directives); i++ { + tag_directive := &emitter.tag_directives[i] + if bytes.HasPrefix(tag, tag_directive.prefix) { + emitter.tag_data.handle = tag_directive.handle + emitter.tag_data.suffix = tag[len(tag_directive.prefix):] + return true + } + } + emitter.tag_data.suffix = tag + return true +} + +// Check if a scalar is valid. +func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { + var ( + block_indicators = false + flow_indicators = false + line_breaks = false + special_characters = false + + leading_space = false + leading_break = false + trailing_space = false + trailing_break = false + break_space = false + space_break = false + + preceded_by_whitespace = false + followed_by_whitespace = false + previous_space = false + previous_break = false + ) + + emitter.scalar_data.value = value + + if len(value) == 0 { + emitter.scalar_data.multiline = false + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = true + emitter.scalar_data.single_quoted_allowed = true + emitter.scalar_data.block_allowed = false + return true + } + + if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) { + block_indicators = true + flow_indicators = true + } + + preceded_by_whitespace = true + for i, w := 0, 0; i < len(value); i += w { + w = width(value[i]) + followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w) + + if i == 0 { + switch value[i] { + case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`': + flow_indicators = true + block_indicators = true + case '?', ':': + flow_indicators = true + if followed_by_whitespace { + block_indicators = true + } + case '-': + if followed_by_whitespace { + flow_indicators = true + block_indicators = true + } + } + } else { + switch value[i] { + case ',', '?', '[', ']', '{', '}': + flow_indicators = true + case ':': + flow_indicators = true + if followed_by_whitespace { + block_indicators = true + } + case '#': + if preceded_by_whitespace { + flow_indicators = true + block_indicators = true + } + } + } + + if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode { + special_characters = true + } + if is_space(value, i) { + if i == 0 { + leading_space = true + } + if i+width(value[i]) == len(value) { + trailing_space = true + } + if previous_break { + break_space = true + } + previous_space = true + previous_break = false + } else if is_break(value, i) { + line_breaks = true + if i == 0 { + leading_break = true + } + if i+width(value[i]) == len(value) { + trailing_break = true + } + if previous_space { + space_break = true + } + previous_space = false + previous_break = true + } else { + previous_space = false + previous_break = false + } + + // [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition. + preceded_by_whitespace = is_blankz(value, i) + } + + emitter.scalar_data.multiline = line_breaks + emitter.scalar_data.flow_plain_allowed = true + emitter.scalar_data.block_plain_allowed = true + emitter.scalar_data.single_quoted_allowed = true + emitter.scalar_data.block_allowed = true + + if leading_space || leading_break || trailing_space || trailing_break { + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = false + } + if trailing_space { + emitter.scalar_data.block_allowed = false + } + if break_space { + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = false + emitter.scalar_data.single_quoted_allowed = false + } + if space_break || special_characters { + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = false + emitter.scalar_data.single_quoted_allowed = false + emitter.scalar_data.block_allowed = false + } + if line_breaks { + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = false + } + if flow_indicators { + emitter.scalar_data.flow_plain_allowed = false + } + if block_indicators { + emitter.scalar_data.block_plain_allowed = false + } + return true +} + +// Check if the event data is valid. +func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool { + + emitter.anchor_data.anchor = nil + emitter.tag_data.handle = nil + emitter.tag_data.suffix = nil + emitter.scalar_data.value = nil + + switch event.typ { + case yaml_ALIAS_EVENT: + if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) { + return false + } + + case yaml_SCALAR_EVENT: + if len(event.anchor) > 0 { + if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { + return false + } + } + if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) { + if !yaml_emitter_analyze_tag(emitter, event.tag) { + return false + } + } + if !yaml_emitter_analyze_scalar(emitter, event.value) { + return false + } + + case yaml_SEQUENCE_START_EVENT: + if len(event.anchor) > 0 { + if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { + return false + } + } + if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { + if !yaml_emitter_analyze_tag(emitter, event.tag) { + return false + } + } + + case yaml_MAPPING_START_EVENT: + if len(event.anchor) > 0 { + if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { + return false + } + } + if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { + if !yaml_emitter_analyze_tag(emitter, event.tag) { + return false + } + } + } + return true +} + +// Write the BOM character. +func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool { + if !flush(emitter) { + return false + } + pos := emitter.buffer_pos + emitter.buffer[pos+0] = '\xEF' + emitter.buffer[pos+1] = '\xBB' + emitter.buffer[pos+2] = '\xBF' + emitter.buffer_pos += 3 + return true +} + +func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool { + indent := emitter.indent + if indent < 0 { + indent = 0 + } + if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) { + if !put_break(emitter) { + return false + } + } + for emitter.column < indent { + if !put(emitter, ' ') { + return false + } + } + emitter.whitespace = true + emitter.indention = true + return true +} + +func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool { + if need_whitespace && !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + if !write_all(emitter, indicator) { + return false + } + emitter.whitespace = is_whitespace + emitter.indention = (emitter.indention && is_indention) + emitter.open_ended = false + return true +} + +func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool { + if !write_all(emitter, value) { + return false + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool { + if !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + if !write_all(emitter, value) { + return false + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool { + if need_whitespace && !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + for i := 0; i < len(value); { + var must_write bool + switch value[i] { + case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']': + must_write = true + default: + must_write = is_alpha(value, i) + } + if must_write { + if !write(emitter, value, &i) { + return false + } + } else { + w := width(value[i]) + for k := 0; k < w; k++ { + octet := value[i] + i++ + if !put(emitter, '%') { + return false + } + + c := octet >> 4 + if c < 10 { + c += '0' + } else { + c += 'A' - 10 + } + if !put(emitter, c) { + return false + } + + c = octet & 0x0f + if c < 10 { + c += '0' + } else { + c += 'A' - 10 + } + if !put(emitter, c) { + return false + } + } + } + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { + if !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + + spaces := false + breaks := false + for i := 0; i < len(value); { + if is_space(value, i) { + if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) { + if !yaml_emitter_write_indent(emitter) { + return false + } + i += width(value[i]) + } else { + if !write(emitter, value, &i) { + return false + } + } + spaces = true + } else if is_break(value, i) { + if !breaks && value[i] == '\n' { + if !put_break(emitter) { + return false + } + } + if !write_break(emitter, value, &i) { + return false + } + emitter.indention = true + breaks = true + } else { + if breaks { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !write(emitter, value, &i) { + return false + } + emitter.indention = false + spaces = false + breaks = false + } + } + + emitter.whitespace = false + emitter.indention = false + if emitter.root_context { + emitter.open_ended = true + } + + return true +} + +func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { + + if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) { + return false + } + + spaces := false + breaks := false + for i := 0; i < len(value); { + if is_space(value, i) { + if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) { + if !yaml_emitter_write_indent(emitter) { + return false + } + i += width(value[i]) + } else { + if !write(emitter, value, &i) { + return false + } + } + spaces = true + } else if is_break(value, i) { + if !breaks && value[i] == '\n' { + if !put_break(emitter) { + return false + } + } + if !write_break(emitter, value, &i) { + return false + } + emitter.indention = true + breaks = true + } else { + if breaks { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if value[i] == '\'' { + if !put(emitter, '\'') { + return false + } + } + if !write(emitter, value, &i) { + return false + } + emitter.indention = false + spaces = false + breaks = false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) { + return false + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { + spaces := false + if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) { + return false + } + + for i := 0; i < len(value); { + if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) || + is_bom(value, i) || is_break(value, i) || + value[i] == '"' || value[i] == '\\' { + + octet := value[i] + + var w int + var v rune + switch { + case octet&0x80 == 0x00: + w, v = 1, rune(octet&0x7F) + case octet&0xE0 == 0xC0: + w, v = 2, rune(octet&0x1F) + case octet&0xF0 == 0xE0: + w, v = 3, rune(octet&0x0F) + case octet&0xF8 == 0xF0: + w, v = 4, rune(octet&0x07) + } + for k := 1; k < w; k++ { + octet = value[i+k] + v = (v << 6) + (rune(octet) & 0x3F) + } + i += w + + if !put(emitter, '\\') { + return false + } + + var ok bool + switch v { + case 0x00: + ok = put(emitter, '0') + case 0x07: + ok = put(emitter, 'a') + case 0x08: + ok = put(emitter, 'b') + case 0x09: + ok = put(emitter, 't') + case 0x0A: + ok = put(emitter, 'n') + case 0x0b: + ok = put(emitter, 'v') + case 0x0c: + ok = put(emitter, 'f') + case 0x0d: + ok = put(emitter, 'r') + case 0x1b: + ok = put(emitter, 'e') + case 0x22: + ok = put(emitter, '"') + case 0x5c: + ok = put(emitter, '\\') + case 0x85: + ok = put(emitter, 'N') + case 0xA0: + ok = put(emitter, '_') + case 0x2028: + ok = put(emitter, 'L') + case 0x2029: + ok = put(emitter, 'P') + default: + if v <= 0xFF { + ok = put(emitter, 'x') + w = 2 + } else if v <= 0xFFFF { + ok = put(emitter, 'u') + w = 4 + } else { + ok = put(emitter, 'U') + w = 8 + } + for k := (w - 1) * 4; ok && k >= 0; k -= 4 { + digit := byte((v >> uint(k)) & 0x0F) + if digit < 10 { + ok = put(emitter, digit+'0') + } else { + ok = put(emitter, digit+'A'-10) + } + } + } + if !ok { + return false + } + spaces = false + } else if is_space(value, i) { + if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 { + if !yaml_emitter_write_indent(emitter) { + return false + } + if is_space(value, i+1) { + if !put(emitter, '\\') { + return false + } + } + i += width(value[i]) + } else if !write(emitter, value, &i) { + return false + } + spaces = true + } else { + if !write(emitter, value, &i) { + return false + } + spaces = false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) { + return false + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool { + if is_space(value, 0) || is_break(value, 0) { + indent_hint := []byte{'0' + byte(emitter.best_indent)} + if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) { + return false + } + } + + emitter.open_ended = false + + var chomp_hint [1]byte + if len(value) == 0 { + chomp_hint[0] = '-' + } else { + i := len(value) - 1 + for value[i]&0xC0 == 0x80 { + i-- + } + if !is_break(value, i) { + chomp_hint[0] = '-' + } else if i == 0 { + chomp_hint[0] = '+' + emitter.open_ended = true + } else { + i-- + for value[i]&0xC0 == 0x80 { + i-- + } + if is_break(value, i) { + chomp_hint[0] = '+' + emitter.open_ended = true + } + } + } + if chomp_hint[0] != 0 { + if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) { + return false + } + } + return true +} + +func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool { + if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) { + return false + } + if !yaml_emitter_write_block_scalar_hints(emitter, value) { + return false + } + if !put_break(emitter) { + return false + } + emitter.indention = true + emitter.whitespace = true + breaks := true + for i := 0; i < len(value); { + if is_break(value, i) { + if !write_break(emitter, value, &i) { + return false + } + emitter.indention = true + breaks = true + } else { + if breaks { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !write(emitter, value, &i) { + return false + } + emitter.indention = false + breaks = false + } + } + + return true +} + +func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool { + if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) { + return false + } + if !yaml_emitter_write_block_scalar_hints(emitter, value) { + return false + } + + if !put_break(emitter) { + return false + } + emitter.indention = true + emitter.whitespace = true + + breaks := true + leading_spaces := true + for i := 0; i < len(value); { + if is_break(value, i) { + if !breaks && !leading_spaces && value[i] == '\n' { + k := 0 + for is_break(value, k) { + k += width(value[k]) + } + if !is_blankz(value, k) { + if !put_break(emitter) { + return false + } + } + } + if !write_break(emitter, value, &i) { + return false + } + emitter.indention = true + breaks = true + } else { + if breaks { + if !yaml_emitter_write_indent(emitter) { + return false + } + leading_spaces = is_blank(value, i) + } + if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width { + if !yaml_emitter_write_indent(emitter) { + return false + } + i += width(value[i]) + } else { + if !write(emitter, value, &i) { + return false + } + } + emitter.indention = false + breaks = false + } + } + return true +} diff --git a/vendor/gopkg.in/yaml.v2/encode.go b/vendor/gopkg.in/yaml.v2/encode.go new file mode 100644 index 0000000..0ee738e --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/encode.go @@ -0,0 +1,390 @@ +package yaml + +import ( + "encoding" + "fmt" + "io" + "reflect" + "regexp" + "sort" + "strconv" + "strings" + "time" + "unicode/utf8" +) + +// jsonNumber is the interface of the encoding/json.Number datatype. +// Repeating the interface here avoids a dependency on encoding/json, and also +// supports other libraries like jsoniter, which use a similar datatype with +// the same interface. Detecting this interface is useful when dealing with +// structures containing json.Number, which is a string under the hood. The +// encoder should prefer the use of Int64(), Float64() and string(), in that +// order, when encoding this type. +type jsonNumber interface { + Float64() (float64, error) + Int64() (int64, error) + String() string +} + +type encoder struct { + emitter yaml_emitter_t + event yaml_event_t + out []byte + flow bool + // doneInit holds whether the initial stream_start_event has been + // emitted. + doneInit bool +} + +func newEncoder() *encoder { + e := &encoder{} + yaml_emitter_initialize(&e.emitter) + yaml_emitter_set_output_string(&e.emitter, &e.out) + yaml_emitter_set_unicode(&e.emitter, true) + return e +} + +func newEncoderWithWriter(w io.Writer) *encoder { + e := &encoder{} + yaml_emitter_initialize(&e.emitter) + yaml_emitter_set_output_writer(&e.emitter, w) + yaml_emitter_set_unicode(&e.emitter, true) + return e +} + +func (e *encoder) init() { + if e.doneInit { + return + } + yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING) + e.emit() + e.doneInit = true +} + +func (e *encoder) finish() { + e.emitter.open_ended = false + yaml_stream_end_event_initialize(&e.event) + e.emit() +} + +func (e *encoder) destroy() { + yaml_emitter_delete(&e.emitter) +} + +func (e *encoder) emit() { + // This will internally delete the e.event value. + e.must(yaml_emitter_emit(&e.emitter, &e.event)) +} + +func (e *encoder) must(ok bool) { + if !ok { + msg := e.emitter.problem + if msg == "" { + msg = "unknown problem generating YAML content" + } + failf("%s", msg) + } +} + +func (e *encoder) marshalDoc(tag string, in reflect.Value) { + e.init() + yaml_document_start_event_initialize(&e.event, nil, nil, true) + e.emit() + e.marshal(tag, in) + yaml_document_end_event_initialize(&e.event, true) + e.emit() +} + +func (e *encoder) marshal(tag string, in reflect.Value) { + if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() { + e.nilv() + return + } + iface := in.Interface() + switch m := iface.(type) { + case jsonNumber: + integer, err := m.Int64() + if err == nil { + // In this case the json.Number is a valid int64 + in = reflect.ValueOf(integer) + break + } + float, err := m.Float64() + if err == nil { + // In this case the json.Number is a valid float64 + in = reflect.ValueOf(float) + break + } + // fallback case - no number could be obtained + in = reflect.ValueOf(m.String()) + case time.Time, *time.Time: + // Although time.Time implements TextMarshaler, + // we don't want to treat it as a string for YAML + // purposes because YAML has special support for + // timestamps. + case Marshaler: + v, err := m.MarshalYAML() + if err != nil { + fail(err) + } + if v == nil { + e.nilv() + return + } + in = reflect.ValueOf(v) + case encoding.TextMarshaler: + text, err := m.MarshalText() + if err != nil { + fail(err) + } + in = reflect.ValueOf(string(text)) + case nil: + e.nilv() + return + } + switch in.Kind() { + case reflect.Interface: + e.marshal(tag, in.Elem()) + case reflect.Map: + e.mapv(tag, in) + case reflect.Ptr: + if in.Type() == ptrTimeType { + e.timev(tag, in.Elem()) + } else { + e.marshal(tag, in.Elem()) + } + case reflect.Struct: + if in.Type() == timeType { + e.timev(tag, in) + } else { + e.structv(tag, in) + } + case reflect.Slice, reflect.Array: + if in.Type().Elem() == mapItemType { + e.itemsv(tag, in) + } else { + e.slicev(tag, in) + } + case reflect.String: + e.stringv(tag, in) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if in.Type() == durationType { + e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String())) + } else { + e.intv(tag, in) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + e.uintv(tag, in) + case reflect.Float32, reflect.Float64: + e.floatv(tag, in) + case reflect.Bool: + e.boolv(tag, in) + default: + panic("cannot marshal type: " + in.Type().String()) + } +} + +func (e *encoder) mapv(tag string, in reflect.Value) { + e.mappingv(tag, func() { + keys := keyList(in.MapKeys()) + sort.Sort(keys) + for _, k := range keys { + e.marshal("", k) + e.marshal("", in.MapIndex(k)) + } + }) +} + +func (e *encoder) itemsv(tag string, in reflect.Value) { + e.mappingv(tag, func() { + slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem) + for _, item := range slice { + e.marshal("", reflect.ValueOf(item.Key)) + e.marshal("", reflect.ValueOf(item.Value)) + } + }) +} + +func (e *encoder) structv(tag string, in reflect.Value) { + sinfo, err := getStructInfo(in.Type()) + if err != nil { + panic(err) + } + e.mappingv(tag, func() { + for _, info := range sinfo.FieldsList { + var value reflect.Value + if info.Inline == nil { + value = in.Field(info.Num) + } else { + value = in.FieldByIndex(info.Inline) + } + if info.OmitEmpty && isZero(value) { + continue + } + e.marshal("", reflect.ValueOf(info.Key)) + e.flow = info.Flow + e.marshal("", value) + } + if sinfo.InlineMap >= 0 { + m := in.Field(sinfo.InlineMap) + if m.Len() > 0 { + e.flow = false + keys := keyList(m.MapKeys()) + sort.Sort(keys) + for _, k := range keys { + if _, found := sinfo.FieldsMap[k.String()]; found { + panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String())) + } + e.marshal("", k) + e.flow = false + e.marshal("", m.MapIndex(k)) + } + } + } + }) +} + +func (e *encoder) mappingv(tag string, f func()) { + implicit := tag == "" + style := yaml_BLOCK_MAPPING_STYLE + if e.flow { + e.flow = false + style = yaml_FLOW_MAPPING_STYLE + } + yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style) + e.emit() + f() + yaml_mapping_end_event_initialize(&e.event) + e.emit() +} + +func (e *encoder) slicev(tag string, in reflect.Value) { + implicit := tag == "" + style := yaml_BLOCK_SEQUENCE_STYLE + if e.flow { + e.flow = false + style = yaml_FLOW_SEQUENCE_STYLE + } + e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) + e.emit() + n := in.Len() + for i := 0; i < n; i++ { + e.marshal("", in.Index(i)) + } + e.must(yaml_sequence_end_event_initialize(&e.event)) + e.emit() +} + +// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1. +// +// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported +// in YAML 1.2 and by this package, but these should be marshalled quoted for +// the time being for compatibility with other parsers. +func isBase60Float(s string) (result bool) { + // Fast path. + if s == "" { + return false + } + c := s[0] + if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 { + return false + } + // Do the full match. + return base60float.MatchString(s) +} + +// From http://yaml.org/type/float.html, except the regular expression there +// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix. +var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`) + +func (e *encoder) stringv(tag string, in reflect.Value) { + var style yaml_scalar_style_t + s := in.String() + canUsePlain := true + switch { + case !utf8.ValidString(s): + if tag == yaml_BINARY_TAG { + failf("explicitly tagged !!binary data must be base64-encoded") + } + if tag != "" { + failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) + } + // It can't be encoded directly as YAML so use a binary tag + // and encode it as base64. + tag = yaml_BINARY_TAG + s = encodeBase64(s) + case tag == "": + // Check to see if it would resolve to a specific + // tag when encoded unquoted. If it doesn't, + // there's no need to quote it. + rtag, _ := resolve("", s) + canUsePlain = rtag == yaml_STR_TAG && !isBase60Float(s) + } + // Note: it's possible for user code to emit invalid YAML + // if they explicitly specify a tag and a string containing + // text that's incompatible with that tag. + switch { + case strings.Contains(s, "\n"): + style = yaml_LITERAL_SCALAR_STYLE + case canUsePlain: + style = yaml_PLAIN_SCALAR_STYLE + default: + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + e.emitScalar(s, "", tag, style) +} + +func (e *encoder) boolv(tag string, in reflect.Value) { + var s string + if in.Bool() { + s = "true" + } else { + s = "false" + } + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) +} + +func (e *encoder) intv(tag string, in reflect.Value) { + s := strconv.FormatInt(in.Int(), 10) + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) +} + +func (e *encoder) uintv(tag string, in reflect.Value) { + s := strconv.FormatUint(in.Uint(), 10) + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) +} + +func (e *encoder) timev(tag string, in reflect.Value) { + t := in.Interface().(time.Time) + s := t.Format(time.RFC3339Nano) + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) +} + +func (e *encoder) floatv(tag string, in reflect.Value) { + // Issue #352: When formatting, use the precision of the underlying value + precision := 64 + if in.Kind() == reflect.Float32 { + precision = 32 + } + + s := strconv.FormatFloat(in.Float(), 'g', -1, precision) + switch s { + case "+Inf": + s = ".inf" + case "-Inf": + s = "-.inf" + case "NaN": + s = ".nan" + } + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) +} + +func (e *encoder) nilv() { + e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE) +} + +func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) { + implicit := tag == "" + e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style)) + e.emit() +} diff --git a/vendor/gopkg.in/yaml.v2/go.mod b/vendor/gopkg.in/yaml.v2/go.mod new file mode 100644 index 0000000..1934e87 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/go.mod @@ -0,0 +1,5 @@ +module "gopkg.in/yaml.v2" + +require ( + "gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405 +) diff --git a/vendor/gopkg.in/yaml.v2/parserc.go b/vendor/gopkg.in/yaml.v2/parserc.go new file mode 100644 index 0000000..81d05df --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/parserc.go @@ -0,0 +1,1095 @@ +package yaml + +import ( + "bytes" +) + +// The parser implements the following grammar: +// +// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END +// implicit_document ::= block_node DOCUMENT-END* +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* +// block_node_or_indentless_sequence ::= +// ALIAS +// | properties (block_content | indentless_block_sequence)? +// | block_content +// | indentless_block_sequence +// block_node ::= ALIAS +// | properties block_content? +// | block_content +// flow_node ::= ALIAS +// | properties flow_content? +// | flow_content +// properties ::= TAG ANCHOR? | ANCHOR TAG? +// block_content ::= block_collection | flow_collection | SCALAR +// flow_content ::= flow_collection | SCALAR +// block_collection ::= block_sequence | block_mapping +// flow_collection ::= flow_sequence | flow_mapping +// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END +// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ +// block_mapping ::= BLOCK-MAPPING_START +// ((KEY block_node_or_indentless_sequence?)? +// (VALUE block_node_or_indentless_sequence?)?)* +// BLOCK-END +// flow_sequence ::= FLOW-SEQUENCE-START +// (flow_sequence_entry FLOW-ENTRY)* +// flow_sequence_entry? +// FLOW-SEQUENCE-END +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// flow_mapping ::= FLOW-MAPPING-START +// (flow_mapping_entry FLOW-ENTRY)* +// flow_mapping_entry? +// FLOW-MAPPING-END +// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + +// Peek the next token in the token queue. +func peek_token(parser *yaml_parser_t) *yaml_token_t { + if parser.token_available || yaml_parser_fetch_more_tokens(parser) { + return &parser.tokens[parser.tokens_head] + } + return nil +} + +// Remove the next token from the queue (must be called after peek_token). +func skip_token(parser *yaml_parser_t) { + parser.token_available = false + parser.tokens_parsed++ + parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN + parser.tokens_head++ +} + +// Get the next event. +func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool { + // Erase the event object. + *event = yaml_event_t{} + + // No events after the end of the stream or error. + if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE { + return true + } + + // Generate the next event. + return yaml_parser_state_machine(parser, event) +} + +// Set parser error. +func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool { + parser.error = yaml_PARSER_ERROR + parser.problem = problem + parser.problem_mark = problem_mark + return false +} + +func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool { + parser.error = yaml_PARSER_ERROR + parser.context = context + parser.context_mark = context_mark + parser.problem = problem + parser.problem_mark = problem_mark + return false +} + +// State dispatcher. +func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool { + //trace("yaml_parser_state_machine", "state:", parser.state.String()) + + switch parser.state { + case yaml_PARSE_STREAM_START_STATE: + return yaml_parser_parse_stream_start(parser, event) + + case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: + return yaml_parser_parse_document_start(parser, event, true) + + case yaml_PARSE_DOCUMENT_START_STATE: + return yaml_parser_parse_document_start(parser, event, false) + + case yaml_PARSE_DOCUMENT_CONTENT_STATE: + return yaml_parser_parse_document_content(parser, event) + + case yaml_PARSE_DOCUMENT_END_STATE: + return yaml_parser_parse_document_end(parser, event) + + case yaml_PARSE_BLOCK_NODE_STATE: + return yaml_parser_parse_node(parser, event, true, false) + + case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: + return yaml_parser_parse_node(parser, event, true, true) + + case yaml_PARSE_FLOW_NODE_STATE: + return yaml_parser_parse_node(parser, event, false, false) + + case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: + return yaml_parser_parse_block_sequence_entry(parser, event, true) + + case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_block_sequence_entry(parser, event, false) + + case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_indentless_sequence_entry(parser, event) + + case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_parser_parse_block_mapping_key(parser, event, true) + + case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: + return yaml_parser_parse_block_mapping_key(parser, event, false) + + case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: + return yaml_parser_parse_block_mapping_value(parser, event) + + case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: + return yaml_parser_parse_flow_sequence_entry(parser, event, true) + + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_flow_sequence_entry(parser, event, false) + + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event) + + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event) + + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event) + + case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_parser_parse_flow_mapping_key(parser, event, true) + + case yaml_PARSE_FLOW_MAPPING_KEY_STATE: + return yaml_parser_parse_flow_mapping_key(parser, event, false) + + case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: + return yaml_parser_parse_flow_mapping_value(parser, event, false) + + case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: + return yaml_parser_parse_flow_mapping_value(parser, event, true) + + default: + panic("invalid parser state") + } +} + +// Parse the production: +// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END +// ************ +func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_STREAM_START_TOKEN { + return yaml_parser_set_parser_error(parser, "did not find expected ", token.start_mark) + } + parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE + *event = yaml_event_t{ + typ: yaml_STREAM_START_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + encoding: token.encoding, + } + skip_token(parser) + return true +} + +// Parse the productions: +// implicit_document ::= block_node DOCUMENT-END* +// * +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* +// ************************* +func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool { + + token := peek_token(parser) + if token == nil { + return false + } + + // Parse extra document end indicators. + if !implicit { + for token.typ == yaml_DOCUMENT_END_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } + } + + if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN && + token.typ != yaml_TAG_DIRECTIVE_TOKEN && + token.typ != yaml_DOCUMENT_START_TOKEN && + token.typ != yaml_STREAM_END_TOKEN { + // Parse an implicit document. + if !yaml_parser_process_directives(parser, nil, nil) { + return false + } + parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) + parser.state = yaml_PARSE_BLOCK_NODE_STATE + + *event = yaml_event_t{ + typ: yaml_DOCUMENT_START_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + + } else if token.typ != yaml_STREAM_END_TOKEN { + // Parse an explicit document. + var version_directive *yaml_version_directive_t + var tag_directives []yaml_tag_directive_t + start_mark := token.start_mark + if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) { + return false + } + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_DOCUMENT_START_TOKEN { + yaml_parser_set_parser_error(parser, + "did not find expected ", token.start_mark) + return false + } + parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) + parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE + end_mark := token.end_mark + + *event = yaml_event_t{ + typ: yaml_DOCUMENT_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + version_directive: version_directive, + tag_directives: tag_directives, + implicit: false, + } + skip_token(parser) + + } else { + // Parse the stream end. + parser.state = yaml_PARSE_END_STATE + *event = yaml_event_t{ + typ: yaml_STREAM_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + skip_token(parser) + } + + return true +} + +// Parse the productions: +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* +// *********** +// +func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_VERSION_DIRECTIVE_TOKEN || + token.typ == yaml_TAG_DIRECTIVE_TOKEN || + token.typ == yaml_DOCUMENT_START_TOKEN || + token.typ == yaml_DOCUMENT_END_TOKEN || + token.typ == yaml_STREAM_END_TOKEN { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + return yaml_parser_process_empty_scalar(parser, event, + token.start_mark) + } + return yaml_parser_parse_node(parser, event, true, false) +} + +// Parse the productions: +// implicit_document ::= block_node DOCUMENT-END* +// ************* +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* +// +func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + + start_mark := token.start_mark + end_mark := token.start_mark + + implicit := true + if token.typ == yaml_DOCUMENT_END_TOKEN { + end_mark = token.end_mark + skip_token(parser) + implicit = false + } + + parser.tag_directives = parser.tag_directives[:0] + + parser.state = yaml_PARSE_DOCUMENT_START_STATE + *event = yaml_event_t{ + typ: yaml_DOCUMENT_END_EVENT, + start_mark: start_mark, + end_mark: end_mark, + implicit: implicit, + } + return true +} + +// Parse the productions: +// block_node_or_indentless_sequence ::= +// ALIAS +// ***** +// | properties (block_content | indentless_block_sequence)? +// ********** * +// | block_content | indentless_block_sequence +// * +// block_node ::= ALIAS +// ***** +// | properties block_content? +// ********** * +// | block_content +// * +// flow_node ::= ALIAS +// ***** +// | properties flow_content? +// ********** * +// | flow_content +// * +// properties ::= TAG ANCHOR? | ANCHOR TAG? +// ************************* +// block_content ::= block_collection | flow_collection | SCALAR +// ****** +// flow_content ::= flow_collection | SCALAR +// ****** +func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool { + //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)() + + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ == yaml_ALIAS_TOKEN { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + *event = yaml_event_t{ + typ: yaml_ALIAS_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + anchor: token.value, + } + skip_token(parser) + return true + } + + start_mark := token.start_mark + end_mark := token.start_mark + + var tag_token bool + var tag_handle, tag_suffix, anchor []byte + var tag_mark yaml_mark_t + if token.typ == yaml_ANCHOR_TOKEN { + anchor = token.value + start_mark = token.start_mark + end_mark = token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_TAG_TOKEN { + tag_token = true + tag_handle = token.value + tag_suffix = token.suffix + tag_mark = token.start_mark + end_mark = token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } + } else if token.typ == yaml_TAG_TOKEN { + tag_token = true + tag_handle = token.value + tag_suffix = token.suffix + start_mark = token.start_mark + tag_mark = token.start_mark + end_mark = token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_ANCHOR_TOKEN { + anchor = token.value + end_mark = token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } + } + + var tag []byte + if tag_token { + if len(tag_handle) == 0 { + tag = tag_suffix + tag_suffix = nil + } else { + for i := range parser.tag_directives { + if bytes.Equal(parser.tag_directives[i].handle, tag_handle) { + tag = append([]byte(nil), parser.tag_directives[i].prefix...) + tag = append(tag, tag_suffix...) + break + } + } + if len(tag) == 0 { + yaml_parser_set_parser_error_context(parser, + "while parsing a node", start_mark, + "found undefined tag handle", tag_mark) + return false + } + } + } + + implicit := len(tag) == 0 + if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN { + end_mark = token.end_mark + parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE + *event = yaml_event_t{ + typ: yaml_SEQUENCE_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), + } + return true + } + if token.typ == yaml_SCALAR_TOKEN { + var plain_implicit, quoted_implicit bool + end_mark = token.end_mark + if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') { + plain_implicit = true + } else if len(tag) == 0 { + quoted_implicit = true + } + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + + *event = yaml_event_t{ + typ: yaml_SCALAR_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + value: token.value, + implicit: plain_implicit, + quoted_implicit: quoted_implicit, + style: yaml_style_t(token.style), + } + skip_token(parser) + return true + } + if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN { + // [Go] Some of the events below can be merged as they differ only on style. + end_mark = token.end_mark + parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE + *event = yaml_event_t{ + typ: yaml_SEQUENCE_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_FLOW_SEQUENCE_STYLE), + } + return true + } + if token.typ == yaml_FLOW_MAPPING_START_TOKEN { + end_mark = token.end_mark + parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE + *event = yaml_event_t{ + typ: yaml_MAPPING_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), + } + return true + } + if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN { + end_mark = token.end_mark + parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE + *event = yaml_event_t{ + typ: yaml_SEQUENCE_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), + } + return true + } + if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN { + end_mark = token.end_mark + parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE + *event = yaml_event_t{ + typ: yaml_MAPPING_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE), + } + return true + } + if len(anchor) > 0 || len(tag) > 0 { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + + *event = yaml_event_t{ + typ: yaml_SCALAR_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + quoted_implicit: false, + style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), + } + return true + } + + context := "while parsing a flow node" + if block { + context = "while parsing a block node" + } + yaml_parser_set_parser_error_context(parser, context, start_mark, + "did not find expected node content", token.start_mark) + return false +} + +// Parse the productions: +// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END +// ******************** *********** * ********* +// +func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { + if first { + token := peek_token(parser) + parser.marks = append(parser.marks, token.start_mark) + skip_token(parser) + } + + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ == yaml_BLOCK_ENTRY_TOKEN { + mark := token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE) + return yaml_parser_parse_node(parser, event, true, false) + } else { + parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) + } + } + if token.typ == yaml_BLOCK_END_TOKEN { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + + *event = yaml_event_t{ + typ: yaml_SEQUENCE_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + + skip_token(parser) + return true + } + + context_mark := parser.marks[len(parser.marks)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + return yaml_parser_set_parser_error_context(parser, + "while parsing a block collection", context_mark, + "did not find expected '-' indicator", token.start_mark) +} + +// Parse the productions: +// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ +// *********** * +func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ == yaml_BLOCK_ENTRY_TOKEN { + mark := token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_BLOCK_ENTRY_TOKEN && + token.typ != yaml_KEY_TOKEN && + token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_BLOCK_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE) + return yaml_parser_parse_node(parser, event, true, false) + } + parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) + } + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + + *event = yaml_event_t{ + typ: yaml_SEQUENCE_END_EVENT, + start_mark: token.start_mark, + end_mark: token.start_mark, // [Go] Shouldn't this be token.end_mark? + } + return true +} + +// Parse the productions: +// block_mapping ::= BLOCK-MAPPING_START +// ******************* +// ((KEY block_node_or_indentless_sequence?)? +// *** * +// (VALUE block_node_or_indentless_sequence?)?)* +// +// BLOCK-END +// ********* +// +func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { + if first { + token := peek_token(parser) + parser.marks = append(parser.marks, token.start_mark) + skip_token(parser) + } + + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ == yaml_KEY_TOKEN { + mark := token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_KEY_TOKEN && + token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_BLOCK_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE) + return yaml_parser_parse_node(parser, event, true, true) + } else { + parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) + } + } else if token.typ == yaml_BLOCK_END_TOKEN { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + *event = yaml_event_t{ + typ: yaml_MAPPING_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + skip_token(parser) + return true + } + + context_mark := parser.marks[len(parser.marks)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + return yaml_parser_set_parser_error_context(parser, + "while parsing a block mapping", context_mark, + "did not find expected key", token.start_mark) +} + +// Parse the productions: +// block_mapping ::= BLOCK-MAPPING_START +// +// ((KEY block_node_or_indentless_sequence?)? +// +// (VALUE block_node_or_indentless_sequence?)?)* +// ***** * +// BLOCK-END +// +// +func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_VALUE_TOKEN { + mark := token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_KEY_TOKEN && + token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_BLOCK_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE) + return yaml_parser_parse_node(parser, event, true, true) + } + parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) + } + parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) +} + +// Parse the productions: +// flow_sequence ::= FLOW-SEQUENCE-START +// ******************* +// (flow_sequence_entry FLOW-ENTRY)* +// * ********** +// flow_sequence_entry? +// * +// FLOW-SEQUENCE-END +// ***************** +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// * +// +func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { + if first { + token := peek_token(parser) + parser.marks = append(parser.marks, token.start_mark) + skip_token(parser) + } + token := peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { + if !first { + if token.typ == yaml_FLOW_ENTRY_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } else { + context_mark := parser.marks[len(parser.marks)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + return yaml_parser_set_parser_error_context(parser, + "while parsing a flow sequence", context_mark, + "did not find expected ',' or ']'", token.start_mark) + } + } + + if token.typ == yaml_KEY_TOKEN { + parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE + *event = yaml_event_t{ + typ: yaml_MAPPING_START_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + implicit: true, + style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), + } + skip_token(parser) + return true + } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + } + + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + + *event = yaml_event_t{ + typ: yaml_SEQUENCE_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + + skip_token(parser) + return true +} + +// +// Parse the productions: +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// *** * +// +func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_FLOW_ENTRY_TOKEN && + token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + mark := token.end_mark + skip_token(parser) + parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) +} + +// Parse the productions: +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// ***** * +// +func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_VALUE_TOKEN { + skip_token(parser) + token := peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + } + parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) +} + +// Parse the productions: +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// * +// +func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE + *event = yaml_event_t{ + typ: yaml_MAPPING_END_EVENT, + start_mark: token.start_mark, + end_mark: token.start_mark, // [Go] Shouldn't this be end_mark? + } + return true +} + +// Parse the productions: +// flow_mapping ::= FLOW-MAPPING-START +// ****************** +// (flow_mapping_entry FLOW-ENTRY)* +// * ********** +// flow_mapping_entry? +// ****************** +// FLOW-MAPPING-END +// **************** +// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// * *** * +// +func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { + if first { + token := peek_token(parser) + parser.marks = append(parser.marks, token.start_mark) + skip_token(parser) + } + + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ != yaml_FLOW_MAPPING_END_TOKEN { + if !first { + if token.typ == yaml_FLOW_ENTRY_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } else { + context_mark := parser.marks[len(parser.marks)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + return yaml_parser_set_parser_error_context(parser, + "while parsing a flow mapping", context_mark, + "did not find expected ',' or '}'", token.start_mark) + } + } + + if token.typ == yaml_KEY_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_FLOW_ENTRY_TOKEN && + token.typ != yaml_FLOW_MAPPING_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } else { + parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) + } + } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + } + + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + *event = yaml_event_t{ + typ: yaml_MAPPING_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + skip_token(parser) + return true +} + +// Parse the productions: +// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// * ***** * +// +func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool { + token := peek_token(parser) + if token == nil { + return false + } + if empty { + parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) + } + if token.typ == yaml_VALUE_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + } + parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) +} + +// Generate an empty scalar event. +func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool { + *event = yaml_event_t{ + typ: yaml_SCALAR_EVENT, + start_mark: mark, + end_mark: mark, + value: nil, // Empty + implicit: true, + style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), + } + return true +} + +var default_tag_directives = []yaml_tag_directive_t{ + {[]byte("!"), []byte("!")}, + {[]byte("!!"), []byte("tag:yaml.org,2002:")}, +} + +// Parse directives. +func yaml_parser_process_directives(parser *yaml_parser_t, + version_directive_ref **yaml_version_directive_t, + tag_directives_ref *[]yaml_tag_directive_t) bool { + + var version_directive *yaml_version_directive_t + var tag_directives []yaml_tag_directive_t + + token := peek_token(parser) + if token == nil { + return false + } + + for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN { + if token.typ == yaml_VERSION_DIRECTIVE_TOKEN { + if version_directive != nil { + yaml_parser_set_parser_error(parser, + "found duplicate %YAML directive", token.start_mark) + return false + } + if token.major != 1 || token.minor != 1 { + yaml_parser_set_parser_error(parser, + "found incompatible YAML document", token.start_mark) + return false + } + version_directive = &yaml_version_directive_t{ + major: token.major, + minor: token.minor, + } + } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN { + value := yaml_tag_directive_t{ + handle: token.value, + prefix: token.prefix, + } + if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) { + return false + } + tag_directives = append(tag_directives, value) + } + + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } + + for i := range default_tag_directives { + if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) { + return false + } + } + + if version_directive_ref != nil { + *version_directive_ref = version_directive + } + if tag_directives_ref != nil { + *tag_directives_ref = tag_directives + } + return true +} + +// Append a tag directive to the directives stack. +func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool { + for i := range parser.tag_directives { + if bytes.Equal(value.handle, parser.tag_directives[i].handle) { + if allow_duplicates { + return true + } + return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark) + } + } + + // [Go] I suspect the copy is unnecessary. This was likely done + // because there was no way to track ownership of the data. + value_copy := yaml_tag_directive_t{ + handle: make([]byte, len(value.handle)), + prefix: make([]byte, len(value.prefix)), + } + copy(value_copy.handle, value.handle) + copy(value_copy.prefix, value.prefix) + parser.tag_directives = append(parser.tag_directives, value_copy) + return true +} diff --git a/vendor/gopkg.in/yaml.v2/readerc.go b/vendor/gopkg.in/yaml.v2/readerc.go new file mode 100644 index 0000000..7c1f5fa --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/readerc.go @@ -0,0 +1,412 @@ +package yaml + +import ( + "io" +) + +// Set the reader error and return 0. +func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool { + parser.error = yaml_READER_ERROR + parser.problem = problem + parser.problem_offset = offset + parser.problem_value = value + return false +} + +// Byte order marks. +const ( + bom_UTF8 = "\xef\xbb\xbf" + bom_UTF16LE = "\xff\xfe" + bom_UTF16BE = "\xfe\xff" +) + +// Determine the input stream encoding by checking the BOM symbol. If no BOM is +// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. +func yaml_parser_determine_encoding(parser *yaml_parser_t) bool { + // Ensure that we had enough bytes in the raw buffer. + for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 { + if !yaml_parser_update_raw_buffer(parser) { + return false + } + } + + // Determine the encoding. + buf := parser.raw_buffer + pos := parser.raw_buffer_pos + avail := len(buf) - pos + if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] { + parser.encoding = yaml_UTF16LE_ENCODING + parser.raw_buffer_pos += 2 + parser.offset += 2 + } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] { + parser.encoding = yaml_UTF16BE_ENCODING + parser.raw_buffer_pos += 2 + parser.offset += 2 + } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] { + parser.encoding = yaml_UTF8_ENCODING + parser.raw_buffer_pos += 3 + parser.offset += 3 + } else { + parser.encoding = yaml_UTF8_ENCODING + } + return true +} + +// Update the raw buffer. +func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool { + size_read := 0 + + // Return if the raw buffer is full. + if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) { + return true + } + + // Return on EOF. + if parser.eof { + return true + } + + // Move the remaining bytes in the raw buffer to the beginning. + if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) { + copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:]) + } + parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos] + parser.raw_buffer_pos = 0 + + // Call the read handler to fill the buffer. + size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)]) + parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read] + if err == io.EOF { + parser.eof = true + } else if err != nil { + return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1) + } + return true +} + +// Ensure that the buffer contains at least `length` characters. +// Return true on success, false on failure. +// +// The length is supposed to be significantly less that the buffer size. +func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool { + if parser.read_handler == nil { + panic("read handler must be set") + } + + // [Go] This function was changed to guarantee the requested length size at EOF. + // The fact we need to do this is pretty awful, but the description above implies + // for that to be the case, and there are tests + + // If the EOF flag is set and the raw buffer is empty, do nothing. + if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) { + // [Go] ACTUALLY! Read the documentation of this function above. + // This is just broken. To return true, we need to have the + // given length in the buffer. Not doing that means every single + // check that calls this function to make sure the buffer has a + // given length is Go) panicking; or C) accessing invalid memory. + //return true + } + + // Return if the buffer contains enough characters. + if parser.unread >= length { + return true + } + + // Determine the input encoding if it is not known yet. + if parser.encoding == yaml_ANY_ENCODING { + if !yaml_parser_determine_encoding(parser) { + return false + } + } + + // Move the unread characters to the beginning of the buffer. + buffer_len := len(parser.buffer) + if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len { + copy(parser.buffer, parser.buffer[parser.buffer_pos:]) + buffer_len -= parser.buffer_pos + parser.buffer_pos = 0 + } else if parser.buffer_pos == buffer_len { + buffer_len = 0 + parser.buffer_pos = 0 + } + + // Open the whole buffer for writing, and cut it before returning. + parser.buffer = parser.buffer[:cap(parser.buffer)] + + // Fill the buffer until it has enough characters. + first := true + for parser.unread < length { + + // Fill the raw buffer if necessary. + if !first || parser.raw_buffer_pos == len(parser.raw_buffer) { + if !yaml_parser_update_raw_buffer(parser) { + parser.buffer = parser.buffer[:buffer_len] + return false + } + } + first = false + + // Decode the raw buffer. + inner: + for parser.raw_buffer_pos != len(parser.raw_buffer) { + var value rune + var width int + + raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos + + // Decode the next character. + switch parser.encoding { + case yaml_UTF8_ENCODING: + // Decode a UTF-8 character. Check RFC 3629 + // (http://www.ietf.org/rfc/rfc3629.txt) for more details. + // + // The following table (taken from the RFC) is used for + // decoding. + // + // Char. number range | UTF-8 octet sequence + // (hexadecimal) | (binary) + // --------------------+------------------------------------ + // 0000 0000-0000 007F | 0xxxxxxx + // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + // + // Additionally, the characters in the range 0xD800-0xDFFF + // are prohibited as they are reserved for use with UTF-16 + // surrogate pairs. + + // Determine the length of the UTF-8 sequence. + octet := parser.raw_buffer[parser.raw_buffer_pos] + switch { + case octet&0x80 == 0x00: + width = 1 + case octet&0xE0 == 0xC0: + width = 2 + case octet&0xF0 == 0xE0: + width = 3 + case octet&0xF8 == 0xF0: + width = 4 + default: + // The leading octet is invalid. + return yaml_parser_set_reader_error(parser, + "invalid leading UTF-8 octet", + parser.offset, int(octet)) + } + + // Check if the raw buffer contains an incomplete character. + if width > raw_unread { + if parser.eof { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-8 octet sequence", + parser.offset, -1) + } + break inner + } + + // Decode the leading octet. + switch { + case octet&0x80 == 0x00: + value = rune(octet & 0x7F) + case octet&0xE0 == 0xC0: + value = rune(octet & 0x1F) + case octet&0xF0 == 0xE0: + value = rune(octet & 0x0F) + case octet&0xF8 == 0xF0: + value = rune(octet & 0x07) + default: + value = 0 + } + + // Check and decode the trailing octets. + for k := 1; k < width; k++ { + octet = parser.raw_buffer[parser.raw_buffer_pos+k] + + // Check if the octet is valid. + if (octet & 0xC0) != 0x80 { + return yaml_parser_set_reader_error(parser, + "invalid trailing UTF-8 octet", + parser.offset+k, int(octet)) + } + + // Decode the octet. + value = (value << 6) + rune(octet&0x3F) + } + + // Check the length of the sequence against the value. + switch { + case width == 1: + case width == 2 && value >= 0x80: + case width == 3 && value >= 0x800: + case width == 4 && value >= 0x10000: + default: + return yaml_parser_set_reader_error(parser, + "invalid length of a UTF-8 sequence", + parser.offset, -1) + } + + // Check the range of the value. + if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF { + return yaml_parser_set_reader_error(parser, + "invalid Unicode character", + parser.offset, int(value)) + } + + case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING: + var low, high int + if parser.encoding == yaml_UTF16LE_ENCODING { + low, high = 0, 1 + } else { + low, high = 1, 0 + } + + // The UTF-16 encoding is not as simple as one might + // naively think. Check RFC 2781 + // (http://www.ietf.org/rfc/rfc2781.txt). + // + // Normally, two subsequent bytes describe a Unicode + // character. However a special technique (called a + // surrogate pair) is used for specifying character + // values larger than 0xFFFF. + // + // A surrogate pair consists of two pseudo-characters: + // high surrogate area (0xD800-0xDBFF) + // low surrogate area (0xDC00-0xDFFF) + // + // The following formulas are used for decoding + // and encoding characters using surrogate pairs: + // + // U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) + // U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) + // W1 = 110110yyyyyyyyyy + // W2 = 110111xxxxxxxxxx + // + // where U is the character value, W1 is the high surrogate + // area, W2 is the low surrogate area. + + // Check for incomplete UTF-16 character. + if raw_unread < 2 { + if parser.eof { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-16 character", + parser.offset, -1) + } + break inner + } + + // Get the character. + value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) + + (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8) + + // Check for unexpected low surrogate area. + if value&0xFC00 == 0xDC00 { + return yaml_parser_set_reader_error(parser, + "unexpected low surrogate area", + parser.offset, int(value)) + } + + // Check for a high surrogate area. + if value&0xFC00 == 0xD800 { + width = 4 + + // Check for incomplete surrogate pair. + if raw_unread < 4 { + if parser.eof { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-16 surrogate pair", + parser.offset, -1) + } + break inner + } + + // Get the next character. + value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) + + (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8) + + // Check for a low surrogate area. + if value2&0xFC00 != 0xDC00 { + return yaml_parser_set_reader_error(parser, + "expected low surrogate area", + parser.offset+2, int(value2)) + } + + // Generate the value of the surrogate pair. + value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF) + } else { + width = 2 + } + + default: + panic("impossible") + } + + // Check if the character is in the allowed range: + // #x9 | #xA | #xD | [#x20-#x7E] (8 bit) + // | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) + // | [#x10000-#x10FFFF] (32 bit) + switch { + case value == 0x09: + case value == 0x0A: + case value == 0x0D: + case value >= 0x20 && value <= 0x7E: + case value == 0x85: + case value >= 0xA0 && value <= 0xD7FF: + case value >= 0xE000 && value <= 0xFFFD: + case value >= 0x10000 && value <= 0x10FFFF: + default: + return yaml_parser_set_reader_error(parser, + "control characters are not allowed", + parser.offset, int(value)) + } + + // Move the raw pointers. + parser.raw_buffer_pos += width + parser.offset += width + + // Finally put the character into the buffer. + if value <= 0x7F { + // 0000 0000-0000 007F . 0xxxxxxx + parser.buffer[buffer_len+0] = byte(value) + buffer_len += 1 + } else if value <= 0x7FF { + // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx + parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6)) + parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F)) + buffer_len += 2 + } else if value <= 0xFFFF { + // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx + parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12)) + parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F)) + parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F)) + buffer_len += 3 + } else { + // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18)) + parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F)) + parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F)) + parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F)) + buffer_len += 4 + } + + parser.unread++ + } + + // On EOF, put NUL into the buffer and return. + if parser.eof { + parser.buffer[buffer_len] = 0 + buffer_len++ + parser.unread++ + break + } + } + // [Go] Read the documentation of this function above. To return true, + // we need to have the given length in the buffer. Not doing that means + // every single check that calls this function to make sure the buffer + // has a given length is Go) panicking; or C) accessing invalid memory. + // This happens here due to the EOF above breaking early. + for buffer_len < length { + parser.buffer[buffer_len] = 0 + buffer_len++ + } + parser.buffer = parser.buffer[:buffer_len] + return true +} diff --git a/vendor/gopkg.in/yaml.v2/resolve.go b/vendor/gopkg.in/yaml.v2/resolve.go new file mode 100644 index 0000000..4120e0c --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/resolve.go @@ -0,0 +1,258 @@ +package yaml + +import ( + "encoding/base64" + "math" + "regexp" + "strconv" + "strings" + "time" +) + +type resolveMapItem struct { + value interface{} + tag string +} + +var resolveTable = make([]byte, 256) +var resolveMap = make(map[string]resolveMapItem) + +func init() { + t := resolveTable + t[int('+')] = 'S' // Sign + t[int('-')] = 'S' + for _, c := range "0123456789" { + t[int(c)] = 'D' // Digit + } + for _, c := range "yYnNtTfFoO~" { + t[int(c)] = 'M' // In map + } + t[int('.')] = '.' // Float (potentially in map) + + var resolveMapList = []struct { + v interface{} + tag string + l []string + }{ + {true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}}, + {true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}}, + {true, yaml_BOOL_TAG, []string{"on", "On", "ON"}}, + {false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}}, + {false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}}, + {false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}}, + {nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}}, + {math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}}, + {math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}}, + {math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}}, + {math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}}, + {"<<", yaml_MERGE_TAG, []string{"<<"}}, + } + + m := resolveMap + for _, item := range resolveMapList { + for _, s := range item.l { + m[s] = resolveMapItem{item.v, item.tag} + } + } +} + +const longTagPrefix = "tag:yaml.org,2002:" + +func shortTag(tag string) string { + // TODO This can easily be made faster and produce less garbage. + if strings.HasPrefix(tag, longTagPrefix) { + return "!!" + tag[len(longTagPrefix):] + } + return tag +} + +func longTag(tag string) string { + if strings.HasPrefix(tag, "!!") { + return longTagPrefix + tag[2:] + } + return tag +} + +func resolvableTag(tag string) bool { + switch tag { + case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG, yaml_TIMESTAMP_TAG: + return true + } + return false +} + +var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`) + +func resolve(tag string, in string) (rtag string, out interface{}) { + if !resolvableTag(tag) { + return tag, in + } + + defer func() { + switch tag { + case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG: + return + case yaml_FLOAT_TAG: + if rtag == yaml_INT_TAG { + switch v := out.(type) { + case int64: + rtag = yaml_FLOAT_TAG + out = float64(v) + return + case int: + rtag = yaml_FLOAT_TAG + out = float64(v) + return + } + } + } + failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag)) + }() + + // Any data is accepted as a !!str or !!binary. + // Otherwise, the prefix is enough of a hint about what it might be. + hint := byte('N') + if in != "" { + hint = resolveTable[in[0]] + } + if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG { + // Handle things we can lookup in a map. + if item, ok := resolveMap[in]; ok { + return item.tag, item.value + } + + // Base 60 floats are a bad idea, were dropped in YAML 1.2, and + // are purposefully unsupported here. They're still quoted on + // the way out for compatibility with other parser, though. + + switch hint { + case 'M': + // We've already checked the map above. + + case '.': + // Not in the map, so maybe a normal float. + floatv, err := strconv.ParseFloat(in, 64) + if err == nil { + return yaml_FLOAT_TAG, floatv + } + + case 'D', 'S': + // Int, float, or timestamp. + // Only try values as a timestamp if the value is unquoted or there's an explicit + // !!timestamp tag. + if tag == "" || tag == yaml_TIMESTAMP_TAG { + t, ok := parseTimestamp(in) + if ok { + return yaml_TIMESTAMP_TAG, t + } + } + + plain := strings.Replace(in, "_", "", -1) + intv, err := strconv.ParseInt(plain, 0, 64) + if err == nil { + if intv == int64(int(intv)) { + return yaml_INT_TAG, int(intv) + } else { + return yaml_INT_TAG, intv + } + } + uintv, err := strconv.ParseUint(plain, 0, 64) + if err == nil { + return yaml_INT_TAG, uintv + } + if yamlStyleFloat.MatchString(plain) { + floatv, err := strconv.ParseFloat(plain, 64) + if err == nil { + return yaml_FLOAT_TAG, floatv + } + } + if strings.HasPrefix(plain, "0b") { + intv, err := strconv.ParseInt(plain[2:], 2, 64) + if err == nil { + if intv == int64(int(intv)) { + return yaml_INT_TAG, int(intv) + } else { + return yaml_INT_TAG, intv + } + } + uintv, err := strconv.ParseUint(plain[2:], 2, 64) + if err == nil { + return yaml_INT_TAG, uintv + } + } else if strings.HasPrefix(plain, "-0b") { + intv, err := strconv.ParseInt("-" + plain[3:], 2, 64) + if err == nil { + if true || intv == int64(int(intv)) { + return yaml_INT_TAG, int(intv) + } else { + return yaml_INT_TAG, intv + } + } + } + default: + panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")") + } + } + return yaml_STR_TAG, in +} + +// encodeBase64 encodes s as base64 that is broken up into multiple lines +// as appropriate for the resulting length. +func encodeBase64(s string) string { + const lineLen = 70 + encLen := base64.StdEncoding.EncodedLen(len(s)) + lines := encLen/lineLen + 1 + buf := make([]byte, encLen*2+lines) + in := buf[0:encLen] + out := buf[encLen:] + base64.StdEncoding.Encode(in, []byte(s)) + k := 0 + for i := 0; i < len(in); i += lineLen { + j := i + lineLen + if j > len(in) { + j = len(in) + } + k += copy(out[k:], in[i:j]) + if lines > 1 { + out[k] = '\n' + k++ + } + } + return string(out[:k]) +} + +// This is a subset of the formats allowed by the regular expression +// defined at http://yaml.org/type/timestamp.html. +var allowedTimestampFormats = []string{ + "2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields. + "2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t". + "2006-1-2 15:4:5.999999999", // space separated with no time zone + "2006-1-2", // date only + // Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5" + // from the set of examples. +} + +// parseTimestamp parses s as a timestamp string and +// returns the timestamp and reports whether it succeeded. +// Timestamp formats are defined at http://yaml.org/type/timestamp.html +func parseTimestamp(s string) (time.Time, bool) { + // TODO write code to check all the formats supported by + // http://yaml.org/type/timestamp.html instead of using time.Parse. + + // Quick check: all date formats start with YYYY-. + i := 0 + for ; i < len(s); i++ { + if c := s[i]; c < '0' || c > '9' { + break + } + } + if i != 4 || i == len(s) || s[i] != '-' { + return time.Time{}, false + } + for _, format := range allowedTimestampFormats { + if t, err := time.Parse(format, s); err == nil { + return t, true + } + } + return time.Time{}, false +} diff --git a/vendor/gopkg.in/yaml.v2/scannerc.go b/vendor/gopkg.in/yaml.v2/scannerc.go new file mode 100644 index 0000000..0b9bb60 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/scannerc.go @@ -0,0 +1,2711 @@ +package yaml + +import ( + "bytes" + "fmt" +) + +// Introduction +// ************ +// +// The following notes assume that you are familiar with the YAML specification +// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in +// some cases we are less restrictive that it requires. +// +// The process of transforming a YAML stream into a sequence of events is +// divided on two steps: Scanning and Parsing. +// +// The Scanner transforms the input stream into a sequence of tokens, while the +// parser transform the sequence of tokens produced by the Scanner into a +// sequence of parsing events. +// +// The Scanner is rather clever and complicated. The Parser, on the contrary, +// is a straightforward implementation of a recursive-descendant parser (or, +// LL(1) parser, as it is usually called). +// +// Actually there are two issues of Scanning that might be called "clever", the +// rest is quite straightforward. The issues are "block collection start" and +// "simple keys". Both issues are explained below in details. +// +// Here the Scanning step is explained and implemented. We start with the list +// of all the tokens produced by the Scanner together with short descriptions. +// +// Now, tokens: +// +// STREAM-START(encoding) # The stream start. +// STREAM-END # The stream end. +// VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. +// TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. +// DOCUMENT-START # '---' +// DOCUMENT-END # '...' +// BLOCK-SEQUENCE-START # Indentation increase denoting a block +// BLOCK-MAPPING-START # sequence or a block mapping. +// BLOCK-END # Indentation decrease. +// FLOW-SEQUENCE-START # '[' +// FLOW-SEQUENCE-END # ']' +// BLOCK-SEQUENCE-START # '{' +// BLOCK-SEQUENCE-END # '}' +// BLOCK-ENTRY # '-' +// FLOW-ENTRY # ',' +// KEY # '?' or nothing (simple keys). +// VALUE # ':' +// ALIAS(anchor) # '*anchor' +// ANCHOR(anchor) # '&anchor' +// TAG(handle,suffix) # '!handle!suffix' +// SCALAR(value,style) # A scalar. +// +// The following two tokens are "virtual" tokens denoting the beginning and the +// end of the stream: +// +// STREAM-START(encoding) +// STREAM-END +// +// We pass the information about the input stream encoding with the +// STREAM-START token. +// +// The next two tokens are responsible for tags: +// +// VERSION-DIRECTIVE(major,minor) +// TAG-DIRECTIVE(handle,prefix) +// +// Example: +// +// %YAML 1.1 +// %TAG ! !foo +// %TAG !yaml! tag:yaml.org,2002: +// --- +// +// The correspoding sequence of tokens: +// +// STREAM-START(utf-8) +// VERSION-DIRECTIVE(1,1) +// TAG-DIRECTIVE("!","!foo") +// TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") +// DOCUMENT-START +// STREAM-END +// +// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole +// line. +// +// The document start and end indicators are represented by: +// +// DOCUMENT-START +// DOCUMENT-END +// +// Note that if a YAML stream contains an implicit document (without '---' +// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be +// produced. +// +// In the following examples, we present whole documents together with the +// produced tokens. +// +// 1. An implicit document: +// +// 'a scalar' +// +// Tokens: +// +// STREAM-START(utf-8) +// SCALAR("a scalar",single-quoted) +// STREAM-END +// +// 2. An explicit document: +// +// --- +// 'a scalar' +// ... +// +// Tokens: +// +// STREAM-START(utf-8) +// DOCUMENT-START +// SCALAR("a scalar",single-quoted) +// DOCUMENT-END +// STREAM-END +// +// 3. Several documents in a stream: +// +// 'a scalar' +// --- +// 'another scalar' +// --- +// 'yet another scalar' +// +// Tokens: +// +// STREAM-START(utf-8) +// SCALAR("a scalar",single-quoted) +// DOCUMENT-START +// SCALAR("another scalar",single-quoted) +// DOCUMENT-START +// SCALAR("yet another scalar",single-quoted) +// STREAM-END +// +// We have already introduced the SCALAR token above. The following tokens are +// used to describe aliases, anchors, tag, and scalars: +// +// ALIAS(anchor) +// ANCHOR(anchor) +// TAG(handle,suffix) +// SCALAR(value,style) +// +// The following series of examples illustrate the usage of these tokens: +// +// 1. A recursive sequence: +// +// &A [ *A ] +// +// Tokens: +// +// STREAM-START(utf-8) +// ANCHOR("A") +// FLOW-SEQUENCE-START +// ALIAS("A") +// FLOW-SEQUENCE-END +// STREAM-END +// +// 2. A tagged scalar: +// +// !!float "3.14" # A good approximation. +// +// Tokens: +// +// STREAM-START(utf-8) +// TAG("!!","float") +// SCALAR("3.14",double-quoted) +// STREAM-END +// +// 3. Various scalar styles: +// +// --- # Implicit empty plain scalars do not produce tokens. +// --- a plain scalar +// --- 'a single-quoted scalar' +// --- "a double-quoted scalar" +// --- |- +// a literal scalar +// --- >- +// a folded +// scalar +// +// Tokens: +// +// STREAM-START(utf-8) +// DOCUMENT-START +// DOCUMENT-START +// SCALAR("a plain scalar",plain) +// DOCUMENT-START +// SCALAR("a single-quoted scalar",single-quoted) +// DOCUMENT-START +// SCALAR("a double-quoted scalar",double-quoted) +// DOCUMENT-START +// SCALAR("a literal scalar",literal) +// DOCUMENT-START +// SCALAR("a folded scalar",folded) +// STREAM-END +// +// Now it's time to review collection-related tokens. We will start with +// flow collections: +// +// FLOW-SEQUENCE-START +// FLOW-SEQUENCE-END +// FLOW-MAPPING-START +// FLOW-MAPPING-END +// FLOW-ENTRY +// KEY +// VALUE +// +// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and +// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' +// correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the +// indicators '?' and ':', which are used for denoting mapping keys and values, +// are represented by the KEY and VALUE tokens. +// +// The following examples show flow collections: +// +// 1. A flow sequence: +// +// [item 1, item 2, item 3] +// +// Tokens: +// +// STREAM-START(utf-8) +// FLOW-SEQUENCE-START +// SCALAR("item 1",plain) +// FLOW-ENTRY +// SCALAR("item 2",plain) +// FLOW-ENTRY +// SCALAR("item 3",plain) +// FLOW-SEQUENCE-END +// STREAM-END +// +// 2. A flow mapping: +// +// { +// a simple key: a value, # Note that the KEY token is produced. +// ? a complex key: another value, +// } +// +// Tokens: +// +// STREAM-START(utf-8) +// FLOW-MAPPING-START +// KEY +// SCALAR("a simple key",plain) +// VALUE +// SCALAR("a value",plain) +// FLOW-ENTRY +// KEY +// SCALAR("a complex key",plain) +// VALUE +// SCALAR("another value",plain) +// FLOW-ENTRY +// FLOW-MAPPING-END +// STREAM-END +// +// A simple key is a key which is not denoted by the '?' indicator. Note that +// the Scanner still produce the KEY token whenever it encounters a simple key. +// +// For scanning block collections, the following tokens are used (note that we +// repeat KEY and VALUE here): +// +// BLOCK-SEQUENCE-START +// BLOCK-MAPPING-START +// BLOCK-END +// BLOCK-ENTRY +// KEY +// VALUE +// +// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation +// increase that precedes a block collection (cf. the INDENT token in Python). +// The token BLOCK-END denote indentation decrease that ends a block collection +// (cf. the DEDENT token in Python). However YAML has some syntax pecularities +// that makes detections of these tokens more complex. +// +// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators +// '-', '?', and ':' correspondingly. +// +// The following examples show how the tokens BLOCK-SEQUENCE-START, +// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: +// +// 1. Block sequences: +// +// - item 1 +// - item 2 +// - +// - item 3.1 +// - item 3.2 +// - +// key 1: value 1 +// key 2: value 2 +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-ENTRY +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 3.1",plain) +// BLOCK-ENTRY +// SCALAR("item 3.2",plain) +// BLOCK-END +// BLOCK-ENTRY +// BLOCK-MAPPING-START +// KEY +// SCALAR("key 1",plain) +// VALUE +// SCALAR("value 1",plain) +// KEY +// SCALAR("key 2",plain) +// VALUE +// SCALAR("value 2",plain) +// BLOCK-END +// BLOCK-END +// STREAM-END +// +// 2. Block mappings: +// +// a simple key: a value # The KEY token is produced here. +// ? a complex key +// : another value +// a mapping: +// key 1: value 1 +// key 2: value 2 +// a sequence: +// - item 1 +// - item 2 +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-MAPPING-START +// KEY +// SCALAR("a simple key",plain) +// VALUE +// SCALAR("a value",plain) +// KEY +// SCALAR("a complex key",plain) +// VALUE +// SCALAR("another value",plain) +// KEY +// SCALAR("a mapping",plain) +// BLOCK-MAPPING-START +// KEY +// SCALAR("key 1",plain) +// VALUE +// SCALAR("value 1",plain) +// KEY +// SCALAR("key 2",plain) +// VALUE +// SCALAR("value 2",plain) +// BLOCK-END +// KEY +// SCALAR("a sequence",plain) +// VALUE +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-END +// BLOCK-END +// STREAM-END +// +// YAML does not always require to start a new block collection from a new +// line. If the current line contains only '-', '?', and ':' indicators, a new +// block collection may start at the current line. The following examples +// illustrate this case: +// +// 1. Collections in a sequence: +// +// - - item 1 +// - item 2 +// - key 1: value 1 +// key 2: value 2 +// - ? complex key +// : complex value +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-END +// BLOCK-ENTRY +// BLOCK-MAPPING-START +// KEY +// SCALAR("key 1",plain) +// VALUE +// SCALAR("value 1",plain) +// KEY +// SCALAR("key 2",plain) +// VALUE +// SCALAR("value 2",plain) +// BLOCK-END +// BLOCK-ENTRY +// BLOCK-MAPPING-START +// KEY +// SCALAR("complex key") +// VALUE +// SCALAR("complex value") +// BLOCK-END +// BLOCK-END +// STREAM-END +// +// 2. Collections in a mapping: +// +// ? a sequence +// : - item 1 +// - item 2 +// ? a mapping +// : key 1: value 1 +// key 2: value 2 +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-MAPPING-START +// KEY +// SCALAR("a sequence",plain) +// VALUE +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-END +// KEY +// SCALAR("a mapping",plain) +// VALUE +// BLOCK-MAPPING-START +// KEY +// SCALAR("key 1",plain) +// VALUE +// SCALAR("value 1",plain) +// KEY +// SCALAR("key 2",plain) +// VALUE +// SCALAR("value 2",plain) +// BLOCK-END +// BLOCK-END +// STREAM-END +// +// YAML also permits non-indented sequences if they are included into a block +// mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: +// +// key: +// - item 1 # BLOCK-SEQUENCE-START is NOT produced here. +// - item 2 +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-MAPPING-START +// KEY +// SCALAR("key",plain) +// VALUE +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-END +// + +// Ensure that the buffer contains the required number of characters. +// Return true on success, false on failure (reader error or memory error). +func cache(parser *yaml_parser_t, length int) bool { + // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B) + return parser.unread >= length || yaml_parser_update_buffer(parser, length) +} + +// Advance the buffer pointer. +func skip(parser *yaml_parser_t) { + parser.mark.index++ + parser.mark.column++ + parser.unread-- + parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) +} + +func skip_line(parser *yaml_parser_t) { + if is_crlf(parser.buffer, parser.buffer_pos) { + parser.mark.index += 2 + parser.mark.column = 0 + parser.mark.line++ + parser.unread -= 2 + parser.buffer_pos += 2 + } else if is_break(parser.buffer, parser.buffer_pos) { + parser.mark.index++ + parser.mark.column = 0 + parser.mark.line++ + parser.unread-- + parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) + } +} + +// Copy a character to a string buffer and advance pointers. +func read(parser *yaml_parser_t, s []byte) []byte { + w := width(parser.buffer[parser.buffer_pos]) + if w == 0 { + panic("invalid character sequence") + } + if len(s) == 0 { + s = make([]byte, 0, 32) + } + if w == 1 && len(s)+w <= cap(s) { + s = s[:len(s)+1] + s[len(s)-1] = parser.buffer[parser.buffer_pos] + parser.buffer_pos++ + } else { + s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...) + parser.buffer_pos += w + } + parser.mark.index++ + parser.mark.column++ + parser.unread-- + return s +} + +// Copy a line break character to a string buffer and advance pointers. +func read_line(parser *yaml_parser_t, s []byte) []byte { + buf := parser.buffer + pos := parser.buffer_pos + switch { + case buf[pos] == '\r' && buf[pos+1] == '\n': + // CR LF . LF + s = append(s, '\n') + parser.buffer_pos += 2 + parser.mark.index++ + parser.unread-- + case buf[pos] == '\r' || buf[pos] == '\n': + // CR|LF . LF + s = append(s, '\n') + parser.buffer_pos += 1 + case buf[pos] == '\xC2' && buf[pos+1] == '\x85': + // NEL . LF + s = append(s, '\n') + parser.buffer_pos += 2 + case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'): + // LS|PS . LS|PS + s = append(s, buf[parser.buffer_pos:pos+3]...) + parser.buffer_pos += 3 + default: + return s + } + parser.mark.index++ + parser.mark.column = 0 + parser.mark.line++ + parser.unread-- + return s +} + +// Get the next token. +func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool { + // Erase the token object. + *token = yaml_token_t{} // [Go] Is this necessary? + + // No tokens after STREAM-END or error. + if parser.stream_end_produced || parser.error != yaml_NO_ERROR { + return true + } + + // Ensure that the tokens queue contains enough tokens. + if !parser.token_available { + if !yaml_parser_fetch_more_tokens(parser) { + return false + } + } + + // Fetch the next token from the queue. + *token = parser.tokens[parser.tokens_head] + parser.tokens_head++ + parser.tokens_parsed++ + parser.token_available = false + + if token.typ == yaml_STREAM_END_TOKEN { + parser.stream_end_produced = true + } + return true +} + +// Set the scanner error and return false. +func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool { + parser.error = yaml_SCANNER_ERROR + parser.context = context + parser.context_mark = context_mark + parser.problem = problem + parser.problem_mark = parser.mark + return false +} + +func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool { + context := "while parsing a tag" + if directive { + context = "while parsing a %TAG directive" + } + return yaml_parser_set_scanner_error(parser, context, context_mark, problem) +} + +func trace(args ...interface{}) func() { + pargs := append([]interface{}{"+++"}, args...) + fmt.Println(pargs...) + pargs = append([]interface{}{"---"}, args...) + return func() { fmt.Println(pargs...) } +} + +// Ensure that the tokens queue contains at least one token which can be +// returned to the Parser. +func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool { + // While we need more tokens to fetch, do it. + for { + if parser.tokens_head != len(parser.tokens) { + // If queue is non-empty, check if any potential simple key may + // occupy the head position. + head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed] + if !ok { + break + } else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok { + return false + } else if !valid { + break + } + } + // Fetch the next token. + if !yaml_parser_fetch_next_token(parser) { + return false + } + } + + parser.token_available = true + return true +} + +// The dispatcher for token fetchers. +func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool { + // Ensure that the buffer is initialized. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + // Check if we just started scanning. Fetch STREAM-START then. + if !parser.stream_start_produced { + return yaml_parser_fetch_stream_start(parser) + } + + // Eat whitespaces and comments until we reach the next token. + if !yaml_parser_scan_to_next_token(parser) { + return false + } + + // Check the indentation level against the current column. + if !yaml_parser_unroll_indent(parser, parser.mark.column) { + return false + } + + // Ensure that the buffer contains at least 4 characters. 4 is the length + // of the longest indicators ('--- ' and '... '). + if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { + return false + } + + // Is it the end of the stream? + if is_z(parser.buffer, parser.buffer_pos) { + return yaml_parser_fetch_stream_end(parser) + } + + // Is it a directive? + if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' { + return yaml_parser_fetch_directive(parser) + } + + buf := parser.buffer + pos := parser.buffer_pos + + // Is it the document start indicator? + if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) { + return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN) + } + + // Is it the document end indicator? + if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) { + return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN) + } + + // Is it the flow sequence start indicator? + if buf[pos] == '[' { + return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN) + } + + // Is it the flow mapping start indicator? + if parser.buffer[parser.buffer_pos] == '{' { + return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN) + } + + // Is it the flow sequence end indicator? + if parser.buffer[parser.buffer_pos] == ']' { + return yaml_parser_fetch_flow_collection_end(parser, + yaml_FLOW_SEQUENCE_END_TOKEN) + } + + // Is it the flow mapping end indicator? + if parser.buffer[parser.buffer_pos] == '}' { + return yaml_parser_fetch_flow_collection_end(parser, + yaml_FLOW_MAPPING_END_TOKEN) + } + + // Is it the flow entry indicator? + if parser.buffer[parser.buffer_pos] == ',' { + return yaml_parser_fetch_flow_entry(parser) + } + + // Is it the block entry indicator? + if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) { + return yaml_parser_fetch_block_entry(parser) + } + + // Is it the key indicator? + if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { + return yaml_parser_fetch_key(parser) + } + + // Is it the value indicator? + if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { + return yaml_parser_fetch_value(parser) + } + + // Is it an alias? + if parser.buffer[parser.buffer_pos] == '*' { + return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN) + } + + // Is it an anchor? + if parser.buffer[parser.buffer_pos] == '&' { + return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN) + } + + // Is it a tag? + if parser.buffer[parser.buffer_pos] == '!' { + return yaml_parser_fetch_tag(parser) + } + + // Is it a literal scalar? + if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 { + return yaml_parser_fetch_block_scalar(parser, true) + } + + // Is it a folded scalar? + if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 { + return yaml_parser_fetch_block_scalar(parser, false) + } + + // Is it a single-quoted scalar? + if parser.buffer[parser.buffer_pos] == '\'' { + return yaml_parser_fetch_flow_scalar(parser, true) + } + + // Is it a double-quoted scalar? + if parser.buffer[parser.buffer_pos] == '"' { + return yaml_parser_fetch_flow_scalar(parser, false) + } + + // Is it a plain scalar? + // + // A plain scalar may start with any non-blank characters except + // + // '-', '?', ':', ',', '[', ']', '{', '}', + // '#', '&', '*', '!', '|', '>', '\'', '\"', + // '%', '@', '`'. + // + // In the block context (and, for the '-' indicator, in the flow context + // too), it may also start with the characters + // + // '-', '?', ':' + // + // if it is followed by a non-space character. + // + // The last rule is more restrictive than the specification requires. + // [Go] Make this logic more reasonable. + //switch parser.buffer[parser.buffer_pos] { + //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`': + //} + if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' || + parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' || + parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' || + parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || + parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' || + parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' || + parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' || + parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' || + parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' || + parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') || + (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) || + (parser.flow_level == 0 && + (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') && + !is_blankz(parser.buffer, parser.buffer_pos+1)) { + return yaml_parser_fetch_plain_scalar(parser) + } + + // If we don't determine the token type so far, it is an error. + return yaml_parser_set_scanner_error(parser, + "while scanning for the next token", parser.mark, + "found character that cannot start any token") +} + +func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) { + if !simple_key.possible { + return false, true + } + + // The 1.2 specification says: + // + // "If the ? indicator is omitted, parsing needs to see past the + // implicit key to recognize it as such. To limit the amount of + // lookahead required, the “:” indicator must appear at most 1024 + // Unicode characters beyond the start of the key. In addition, the key + // is restricted to a single line." + // + if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index { + // Check if the potential simple key to be removed is required. + if simple_key.required { + return false, yaml_parser_set_scanner_error(parser, + "while scanning a simple key", simple_key.mark, + "could not find expected ':'") + } + simple_key.possible = false + return false, true + } + return true, true +} + +// Check if a simple key may start at the current position and add it if +// needed. +func yaml_parser_save_simple_key(parser *yaml_parser_t) bool { + // A simple key is required at the current position if the scanner is in + // the block context and the current column coincides with the indentation + // level. + + required := parser.flow_level == 0 && parser.indent == parser.mark.column + + // + // If the current position may start a simple key, save it. + // + if parser.simple_key_allowed { + simple_key := yaml_simple_key_t{ + possible: true, + required: required, + token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), + mark: parser.mark, + } + + if !yaml_parser_remove_simple_key(parser) { + return false + } + parser.simple_keys[len(parser.simple_keys)-1] = simple_key + parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1 + } + return true +} + +// Remove a potential simple key at the current flow level. +func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool { + i := len(parser.simple_keys) - 1 + if parser.simple_keys[i].possible { + // If the key is required, it is an error. + if parser.simple_keys[i].required { + return yaml_parser_set_scanner_error(parser, + "while scanning a simple key", parser.simple_keys[i].mark, + "could not find expected ':'") + } + // Remove the key from the stack. + parser.simple_keys[i].possible = false + delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number) + } + return true +} + +// max_flow_level limits the flow_level +const max_flow_level = 10000 + +// Increase the flow level and resize the simple key list if needed. +func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool { + // Reset the simple key on the next level. + parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{ + possible: false, + required: false, + token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), + mark: parser.mark, + }) + + // Increase the flow level. + parser.flow_level++ + if parser.flow_level > max_flow_level { + return yaml_parser_set_scanner_error(parser, + "while increasing flow level", parser.simple_keys[len(parser.simple_keys)-1].mark, + fmt.Sprintf("exceeded max depth of %d", max_flow_level)) + } + return true +} + +// Decrease the flow level. +func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool { + if parser.flow_level > 0 { + parser.flow_level-- + last := len(parser.simple_keys) - 1 + delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number) + parser.simple_keys = parser.simple_keys[:last] + } + return true +} + +// max_indents limits the indents stack size +const max_indents = 10000 + +// Push the current indentation level to the stack and set the new level +// the current column is greater than the indentation level. In this case, +// append or insert the specified token into the token queue. +func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool { + // In the flow context, do nothing. + if parser.flow_level > 0 { + return true + } + + if parser.indent < column { + // Push the current indentation level to the stack and set the new + // indentation level. + parser.indents = append(parser.indents, parser.indent) + parser.indent = column + if len(parser.indents) > max_indents { + return yaml_parser_set_scanner_error(parser, + "while increasing indent level", parser.simple_keys[len(parser.simple_keys)-1].mark, + fmt.Sprintf("exceeded max depth of %d", max_indents)) + } + + // Create a token and insert it into the queue. + token := yaml_token_t{ + typ: typ, + start_mark: mark, + end_mark: mark, + } + if number > -1 { + number -= parser.tokens_parsed + } + yaml_insert_token(parser, number, &token) + } + return true +} + +// Pop indentation levels from the indents stack until the current level +// becomes less or equal to the column. For each indentation level, append +// the BLOCK-END token. +func yaml_parser_unroll_indent(parser *yaml_parser_t, column int) bool { + // In the flow context, do nothing. + if parser.flow_level > 0 { + return true + } + + // Loop through the indentation levels in the stack. + for parser.indent > column { + // Create a token and append it to the queue. + token := yaml_token_t{ + typ: yaml_BLOCK_END_TOKEN, + start_mark: parser.mark, + end_mark: parser.mark, + } + yaml_insert_token(parser, -1, &token) + + // Pop the indentation level. + parser.indent = parser.indents[len(parser.indents)-1] + parser.indents = parser.indents[:len(parser.indents)-1] + } + return true +} + +// Initialize the scanner and produce the STREAM-START token. +func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool { + + // Set the initial indentation. + parser.indent = -1 + + // Initialize the simple key stack. + parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) + + parser.simple_keys_by_tok = make(map[int]int) + + // A simple key is allowed at the beginning of the stream. + parser.simple_key_allowed = true + + // We have started. + parser.stream_start_produced = true + + // Create the STREAM-START token and append it to the queue. + token := yaml_token_t{ + typ: yaml_STREAM_START_TOKEN, + start_mark: parser.mark, + end_mark: parser.mark, + encoding: parser.encoding, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the STREAM-END token and shut down the scanner. +func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool { + + // Force new line. + if parser.mark.column != 0 { + parser.mark.column = 0 + parser.mark.line++ + } + + // Reset the indentation level. + if !yaml_parser_unroll_indent(parser, -1) { + return false + } + + // Reset simple keys. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + parser.simple_key_allowed = false + + // Create the STREAM-END token and append it to the queue. + token := yaml_token_t{ + typ: yaml_STREAM_END_TOKEN, + start_mark: parser.mark, + end_mark: parser.mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. +func yaml_parser_fetch_directive(parser *yaml_parser_t) bool { + // Reset the indentation level. + if !yaml_parser_unroll_indent(parser, -1) { + return false + } + + // Reset simple keys. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + parser.simple_key_allowed = false + + // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. + token := yaml_token_t{} + if !yaml_parser_scan_directive(parser, &token) { + return false + } + // Append the token to the queue. + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the DOCUMENT-START or DOCUMENT-END token. +func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool { + // Reset the indentation level. + if !yaml_parser_unroll_indent(parser, -1) { + return false + } + + // Reset simple keys. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + parser.simple_key_allowed = false + + // Consume the token. + start_mark := parser.mark + + skip(parser) + skip(parser) + skip(parser) + + end_mark := parser.mark + + // Create the DOCUMENT-START or DOCUMENT-END token. + token := yaml_token_t{ + typ: typ, + start_mark: start_mark, + end_mark: end_mark, + } + // Append the token to the queue. + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. +func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool { + // The indicators '[' and '{' may start a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // Increase the flow level. + if !yaml_parser_increase_flow_level(parser) { + return false + } + + // A simple key may follow the indicators '[' and '{'. + parser.simple_key_allowed = true + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. + token := yaml_token_t{ + typ: typ, + start_mark: start_mark, + end_mark: end_mark, + } + // Append the token to the queue. + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. +func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool { + // Reset any potential simple key on the current flow level. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // Decrease the flow level. + if !yaml_parser_decrease_flow_level(parser) { + return false + } + + // No simple keys after the indicators ']' and '}'. + parser.simple_key_allowed = false + + // Consume the token. + + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. + token := yaml_token_t{ + typ: typ, + start_mark: start_mark, + end_mark: end_mark, + } + // Append the token to the queue. + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the FLOW-ENTRY token. +func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool { + // Reset any potential simple keys on the current flow level. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // Simple keys are allowed after ','. + parser.simple_key_allowed = true + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the FLOW-ENTRY token and append it to the queue. + token := yaml_token_t{ + typ: yaml_FLOW_ENTRY_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the BLOCK-ENTRY token. +func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool { + // Check if the scanner is in the block context. + if parser.flow_level == 0 { + // Check if we are allowed to start a new entry. + if !parser.simple_key_allowed { + return yaml_parser_set_scanner_error(parser, "", parser.mark, + "block sequence entries are not allowed in this context") + } + // Add the BLOCK-SEQUENCE-START token if needed. + if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) { + return false + } + } else { + // It is an error for the '-' indicator to occur in the flow context, + // but we let the Parser detect and report about it because the Parser + // is able to point to the context. + } + + // Reset any potential simple keys on the current flow level. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // Simple keys are allowed after '-'. + parser.simple_key_allowed = true + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the BLOCK-ENTRY token and append it to the queue. + token := yaml_token_t{ + typ: yaml_BLOCK_ENTRY_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the KEY token. +func yaml_parser_fetch_key(parser *yaml_parser_t) bool { + + // In the block context, additional checks are required. + if parser.flow_level == 0 { + // Check if we are allowed to start a new key (not nessesary simple). + if !parser.simple_key_allowed { + return yaml_parser_set_scanner_error(parser, "", parser.mark, + "mapping keys are not allowed in this context") + } + // Add the BLOCK-MAPPING-START token if needed. + if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { + return false + } + } + + // Reset any potential simple keys on the current flow level. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // Simple keys are allowed after '?' in the block context. + parser.simple_key_allowed = parser.flow_level == 0 + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the KEY token and append it to the queue. + token := yaml_token_t{ + typ: yaml_KEY_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the VALUE token. +func yaml_parser_fetch_value(parser *yaml_parser_t) bool { + + simple_key := &parser.simple_keys[len(parser.simple_keys)-1] + + // Have we found a simple key? + if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok { + return false + + } else if valid { + + // Create the KEY token and insert it into the queue. + token := yaml_token_t{ + typ: yaml_KEY_TOKEN, + start_mark: simple_key.mark, + end_mark: simple_key.mark, + } + yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token) + + // In the block context, we may need to add the BLOCK-MAPPING-START token. + if !yaml_parser_roll_indent(parser, simple_key.mark.column, + simple_key.token_number, + yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) { + return false + } + + // Remove the simple key. + simple_key.possible = false + delete(parser.simple_keys_by_tok, simple_key.token_number) + + // A simple key cannot follow another simple key. + parser.simple_key_allowed = false + + } else { + // The ':' indicator follows a complex key. + + // In the block context, extra checks are required. + if parser.flow_level == 0 { + + // Check if we are allowed to start a complex value. + if !parser.simple_key_allowed { + return yaml_parser_set_scanner_error(parser, "", parser.mark, + "mapping values are not allowed in this context") + } + + // Add the BLOCK-MAPPING-START token if needed. + if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { + return false + } + } + + // Simple keys after ':' are allowed in the block context. + parser.simple_key_allowed = parser.flow_level == 0 + } + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the VALUE token and append it to the queue. + token := yaml_token_t{ + typ: yaml_VALUE_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the ALIAS or ANCHOR token. +func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool { + // An anchor or an alias could be a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // A simple key cannot follow an anchor or an alias. + parser.simple_key_allowed = false + + // Create the ALIAS or ANCHOR token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_anchor(parser, &token, typ) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the TAG token. +func yaml_parser_fetch_tag(parser *yaml_parser_t) bool { + // A tag could be a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // A simple key cannot follow a tag. + parser.simple_key_allowed = false + + // Create the TAG token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_tag(parser, &token) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. +func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool { + // Remove any potential simple keys. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // A simple key may follow a block scalar. + parser.simple_key_allowed = true + + // Create the SCALAR token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_block_scalar(parser, &token, literal) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. +func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool { + // A plain scalar could be a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // A simple key cannot follow a flow scalar. + parser.simple_key_allowed = false + + // Create the SCALAR token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_flow_scalar(parser, &token, single) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the SCALAR(...,plain) token. +func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool { + // A plain scalar could be a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // A simple key cannot follow a flow scalar. + parser.simple_key_allowed = false + + // Create the SCALAR token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_plain_scalar(parser, &token) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Eat whitespaces and comments until the next token is found. +func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool { + + // Until the next token is not found. + for { + // Allow the BOM mark to start a line. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) { + skip(parser) + } + + // Eat whitespaces. + // Tabs are allowed: + // - in the flow context + // - in the block context, but not at the beginning of the line or + // after '-', '?', or ':' (complex value). + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Eat a comment until a line break. + if parser.buffer[parser.buffer_pos] == '#' { + for !is_breakz(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + } + + // If it is a line break, eat it. + if is_break(parser.buffer, parser.buffer_pos) { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + + // In the block context, a new line may start a simple key. + if parser.flow_level == 0 { + parser.simple_key_allowed = true + } + } else { + break // We have found a token. + } + } + + return true +} + +// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. +// +// Scope: +// %YAML 1.1 # a comment \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// +func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool { + // Eat '%'. + start_mark := parser.mark + skip(parser) + + // Scan the directive name. + var name []byte + if !yaml_parser_scan_directive_name(parser, start_mark, &name) { + return false + } + + // Is it a YAML directive? + if bytes.Equal(name, []byte("YAML")) { + // Scan the VERSION directive value. + var major, minor int8 + if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) { + return false + } + end_mark := parser.mark + + // Create a VERSION-DIRECTIVE token. + *token = yaml_token_t{ + typ: yaml_VERSION_DIRECTIVE_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + major: major, + minor: minor, + } + + // Is it a TAG directive? + } else if bytes.Equal(name, []byte("TAG")) { + // Scan the TAG directive value. + var handle, prefix []byte + if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) { + return false + } + end_mark := parser.mark + + // Create a TAG-DIRECTIVE token. + *token = yaml_token_t{ + typ: yaml_TAG_DIRECTIVE_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: handle, + prefix: prefix, + } + + // Unknown directive. + } else { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "found unknown directive name") + return false + } + + // Eat the rest of the line including any comments. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + if parser.buffer[parser.buffer_pos] == '#' { + for !is_breakz(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + } + + // Check if we are at the end of the line. + if !is_breakz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "did not find expected comment or line break") + return false + } + + // Eat a line break. + if is_break(parser.buffer, parser.buffer_pos) { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + } + + return true +} + +// Scan the directive name. +// +// Scope: +// %YAML 1.1 # a comment \n +// ^^^^ +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^ +// +func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool { + // Consume the directive name. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + var s []byte + for is_alpha(parser.buffer, parser.buffer_pos) { + s = read(parser, s) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check if the name is empty. + if len(s) == 0 { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "could not find expected directive name") + return false + } + + // Check for an blank character after the name. + if !is_blankz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "found unexpected non-alphabetical character") + return false + } + *name = s + return true +} + +// Scan the value of VERSION-DIRECTIVE. +// +// Scope: +// %YAML 1.1 # a comment \n +// ^^^^^^ +func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool { + // Eat whitespaces. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Consume the major version number. + if !yaml_parser_scan_version_directive_number(parser, start_mark, major) { + return false + } + + // Eat '.'. + if parser.buffer[parser.buffer_pos] != '.' { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "did not find expected digit or '.' character") + } + + skip(parser) + + // Consume the minor version number. + if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) { + return false + } + return true +} + +const max_number_length = 2 + +// Scan the version number of VERSION-DIRECTIVE. +// +// Scope: +// %YAML 1.1 # a comment \n +// ^ +// %YAML 1.1 # a comment \n +// ^ +func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool { + + // Repeat while the next character is digit. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + var value, length int8 + for is_digit(parser.buffer, parser.buffer_pos) { + // Check if the number is too long. + length++ + if length > max_number_length { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "found extremely long version number") + } + value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos)) + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check if the number was present. + if length == 0 { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "did not find expected version number") + } + *number = value + return true +} + +// Scan the value of a TAG-DIRECTIVE token. +// +// Scope: +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// +func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool { + var handle_value, prefix_value []byte + + // Eat whitespaces. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Scan a handle. + if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) { + return false + } + + // Expect a whitespace. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if !is_blank(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", + start_mark, "did not find expected whitespace") + return false + } + + // Eat whitespaces. + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Scan a prefix. + if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) { + return false + } + + // Expect a whitespace or line break. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if !is_blankz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", + start_mark, "did not find expected whitespace or line break") + return false + } + + *handle = handle_value + *prefix = prefix_value + return true +} + +func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool { + var s []byte + + // Eat the indicator character. + start_mark := parser.mark + skip(parser) + + // Consume the value. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for is_alpha(parser.buffer, parser.buffer_pos) { + s = read(parser, s) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + end_mark := parser.mark + + /* + * Check if length of the anchor is greater than 0 and it is followed by + * a whitespace character or one of the indicators: + * + * '?', ':', ',', ']', '}', '%', '@', '`'. + */ + + if len(s) == 0 || + !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' || + parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' || + parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' || + parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' || + parser.buffer[parser.buffer_pos] == '`') { + context := "while scanning an alias" + if typ == yaml_ANCHOR_TOKEN { + context = "while scanning an anchor" + } + yaml_parser_set_scanner_error(parser, context, start_mark, + "did not find expected alphabetic or numeric character") + return false + } + + // Create a token. + *token = yaml_token_t{ + typ: typ, + start_mark: start_mark, + end_mark: end_mark, + value: s, + } + + return true +} + +/* + * Scan a TAG token. + */ + +func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool { + var handle, suffix []byte + + start_mark := parser.mark + + // Check if the tag is in the canonical form. + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + + if parser.buffer[parser.buffer_pos+1] == '<' { + // Keep the handle as '' + + // Eat '!<' + skip(parser) + skip(parser) + + // Consume the tag value. + if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { + return false + } + + // Check for '>' and eat it. + if parser.buffer[parser.buffer_pos] != '>' { + yaml_parser_set_scanner_error(parser, "while scanning a tag", + start_mark, "did not find the expected '>'") + return false + } + + skip(parser) + } else { + // The tag has either the '!suffix' or the '!handle!suffix' form. + + // First, try to scan a handle. + if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) { + return false + } + + // Check if it is, indeed, handle. + if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' { + // Scan the suffix now. + if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { + return false + } + } else { + // It wasn't a handle after all. Scan the rest of the tag. + if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) { + return false + } + + // Set the handle to '!'. + handle = []byte{'!'} + + // A special case: the '!' tag. Set the handle to '' and the + // suffix to '!'. + if len(suffix) == 0 { + handle, suffix = suffix, handle + } + } + } + + // Check the character which ends the tag. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if !is_blankz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a tag", + start_mark, "did not find expected whitespace or line break") + return false + } + + end_mark := parser.mark + + // Create a token. + *token = yaml_token_t{ + typ: yaml_TAG_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: handle, + suffix: suffix, + } + return true +} + +// Scan a tag handle. +func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool { + // Check the initial '!' character. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if parser.buffer[parser.buffer_pos] != '!' { + yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "did not find expected '!'") + return false + } + + var s []byte + + // Copy the '!' character. + s = read(parser, s) + + // Copy all subsequent alphabetical and numerical characters. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + for is_alpha(parser.buffer, parser.buffer_pos) { + s = read(parser, s) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check if the trailing character is '!' and copy it. + if parser.buffer[parser.buffer_pos] == '!' { + s = read(parser, s) + } else { + // It's either the '!' tag or not really a tag handle. If it's a %TAG + // directive, it's an error. If it's a tag token, it must be a part of URI. + if directive && string(s) != "!" { + yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "did not find expected '!'") + return false + } + } + + *handle = s + return true +} + +// Scan a tag. +func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool { + //size_t length = head ? strlen((char *)head) : 0 + var s []byte + hasTag := len(head) > 0 + + // Copy the head if needed. + // + // Note that we don't copy the leading '!' character. + if len(head) > 1 { + s = append(s, head[1:]...) + } + + // Scan the tag. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + // The set of characters that may appear in URI is as follows: + // + // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', + // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', + // '%'. + // [Go] Convert this into more reasonable logic. + for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' || + parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' || + parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' || + parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' || + parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' || + parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' || + parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' || + parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' || + parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' || + parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' || + parser.buffer[parser.buffer_pos] == '%' { + // Check if it is a URI-escape sequence. + if parser.buffer[parser.buffer_pos] == '%' { + if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) { + return false + } + } else { + s = read(parser, s) + } + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + hasTag = true + } + + if !hasTag { + yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "did not find expected tag URI") + return false + } + *uri = s + return true +} + +// Decode an URI-escape sequence corresponding to a single UTF-8 character. +func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool { + + // Decode the required number of characters. + w := 1024 + for w > 0 { + // Check for a URI-escaped octet. + if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { + return false + } + + if !(parser.buffer[parser.buffer_pos] == '%' && + is_hex(parser.buffer, parser.buffer_pos+1) && + is_hex(parser.buffer, parser.buffer_pos+2)) { + return yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "did not find URI escaped octet") + } + + // Get the octet. + octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2)) + + // If it is the leading octet, determine the length of the UTF-8 sequence. + if w == 1024 { + w = width(octet) + if w == 0 { + return yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "found an incorrect leading UTF-8 octet") + } + } else { + // Check if the trailing octet is correct. + if octet&0xC0 != 0x80 { + return yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "found an incorrect trailing UTF-8 octet") + } + } + + // Copy the octet and move the pointers. + *s = append(*s, octet) + skip(parser) + skip(parser) + skip(parser) + w-- + } + return true +} + +// Scan a block scalar. +func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool { + // Eat the indicator '|' or '>'. + start_mark := parser.mark + skip(parser) + + // Scan the additional block scalar indicators. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + // Check for a chomping indicator. + var chomping, increment int + if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { + // Set the chomping method and eat the indicator. + if parser.buffer[parser.buffer_pos] == '+' { + chomping = +1 + } else { + chomping = -1 + } + skip(parser) + + // Check for an indentation indicator. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if is_digit(parser.buffer, parser.buffer_pos) { + // Check that the indentation is greater than 0. + if parser.buffer[parser.buffer_pos] == '0' { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found an indentation indicator equal to 0") + return false + } + + // Get the indentation level and eat the indicator. + increment = as_digit(parser.buffer, parser.buffer_pos) + skip(parser) + } + + } else if is_digit(parser.buffer, parser.buffer_pos) { + // Do the same as above, but in the opposite order. + + if parser.buffer[parser.buffer_pos] == '0' { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found an indentation indicator equal to 0") + return false + } + increment = as_digit(parser.buffer, parser.buffer_pos) + skip(parser) + + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { + if parser.buffer[parser.buffer_pos] == '+' { + chomping = +1 + } else { + chomping = -1 + } + skip(parser) + } + } + + // Eat whitespaces and comments to the end of the line. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + if parser.buffer[parser.buffer_pos] == '#' { + for !is_breakz(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + } + + // Check if we are at the end of the line. + if !is_breakz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "did not find expected comment or line break") + return false + } + + // Eat a line break. + if is_break(parser.buffer, parser.buffer_pos) { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + } + + end_mark := parser.mark + + // Set the indentation level if it was specified. + var indent int + if increment > 0 { + if parser.indent >= 0 { + indent = parser.indent + increment + } else { + indent = increment + } + } + + // Scan the leading line breaks and determine the indentation level if needed. + var s, leading_break, trailing_breaks []byte + if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { + return false + } + + // Scan the block scalar content. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + var leading_blank, trailing_blank bool + for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) { + // We are at the beginning of a non-empty line. + + // Is it a trailing whitespace? + trailing_blank = is_blank(parser.buffer, parser.buffer_pos) + + // Check if we need to fold the leading line break. + if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' { + // Do we need to join the lines by space? + if len(trailing_breaks) == 0 { + s = append(s, ' ') + } + } else { + s = append(s, leading_break...) + } + leading_break = leading_break[:0] + + // Append the remaining line breaks. + s = append(s, trailing_breaks...) + trailing_breaks = trailing_breaks[:0] + + // Is it a leading whitespace? + leading_blank = is_blank(parser.buffer, parser.buffer_pos) + + // Consume the current line. + for !is_breakz(parser.buffer, parser.buffer_pos) { + s = read(parser, s) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Consume the line break. + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + + leading_break = read_line(parser, leading_break) + + // Eat the following indentation spaces and line breaks. + if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { + return false + } + } + + // Chomp the tail. + if chomping != -1 { + s = append(s, leading_break...) + } + if chomping == 1 { + s = append(s, trailing_breaks...) + } + + // Create a token. + *token = yaml_token_t{ + typ: yaml_SCALAR_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: s, + style: yaml_LITERAL_SCALAR_STYLE, + } + if !literal { + token.style = yaml_FOLDED_SCALAR_STYLE + } + return true +} + +// Scan indentation spaces and line breaks for a block scalar. Determine the +// indentation level if needed. +func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool { + *end_mark = parser.mark + + // Eat the indentation spaces and line breaks. + max_indent := 0 + for { + // Eat the indentation spaces. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + if parser.mark.column > max_indent { + max_indent = parser.mark.column + } + + // Check for a tab character messing the indentation. + if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) { + return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found a tab character where an indentation space is expected") + } + + // Have we found a non-empty line? + if !is_break(parser.buffer, parser.buffer_pos) { + break + } + + // Consume the line break. + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + // [Go] Should really be returning breaks instead. + *breaks = read_line(parser, *breaks) + *end_mark = parser.mark + } + + // Determine the indentation level if needed. + if *indent == 0 { + *indent = max_indent + if *indent < parser.indent+1 { + *indent = parser.indent + 1 + } + if *indent < 1 { + *indent = 1 + } + } + return true +} + +// Scan a quoted scalar. +func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool { + // Eat the left quote. + start_mark := parser.mark + skip(parser) + + // Consume the content of the quoted scalar. + var s, leading_break, trailing_breaks, whitespaces []byte + for { + // Check that there are no document indicators at the beginning of the line. + if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { + return false + } + + if parser.mark.column == 0 && + ((parser.buffer[parser.buffer_pos+0] == '-' && + parser.buffer[parser.buffer_pos+1] == '-' && + parser.buffer[parser.buffer_pos+2] == '-') || + (parser.buffer[parser.buffer_pos+0] == '.' && + parser.buffer[parser.buffer_pos+1] == '.' && + parser.buffer[parser.buffer_pos+2] == '.')) && + is_blankz(parser.buffer, parser.buffer_pos+3) { + yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", + start_mark, "found unexpected document indicator") + return false + } + + // Check for EOF. + if is_z(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", + start_mark, "found unexpected end of stream") + return false + } + + // Consume non-blank characters. + leading_blanks := false + for !is_blankz(parser.buffer, parser.buffer_pos) { + if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' { + // Is is an escaped single quote. + s = append(s, '\'') + skip(parser) + skip(parser) + + } else if single && parser.buffer[parser.buffer_pos] == '\'' { + // It is a right single quote. + break + } else if !single && parser.buffer[parser.buffer_pos] == '"' { + // It is a right double quote. + break + + } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) { + // It is an escaped line break. + if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { + return false + } + skip(parser) + skip_line(parser) + leading_blanks = true + break + + } else if !single && parser.buffer[parser.buffer_pos] == '\\' { + // It is an escape sequence. + code_length := 0 + + // Check the escape character. + switch parser.buffer[parser.buffer_pos+1] { + case '0': + s = append(s, 0) + case 'a': + s = append(s, '\x07') + case 'b': + s = append(s, '\x08') + case 't', '\t': + s = append(s, '\x09') + case 'n': + s = append(s, '\x0A') + case 'v': + s = append(s, '\x0B') + case 'f': + s = append(s, '\x0C') + case 'r': + s = append(s, '\x0D') + case 'e': + s = append(s, '\x1B') + case ' ': + s = append(s, '\x20') + case '"': + s = append(s, '"') + case '\'': + s = append(s, '\'') + case '\\': + s = append(s, '\\') + case 'N': // NEL (#x85) + s = append(s, '\xC2') + s = append(s, '\x85') + case '_': // #xA0 + s = append(s, '\xC2') + s = append(s, '\xA0') + case 'L': // LS (#x2028) + s = append(s, '\xE2') + s = append(s, '\x80') + s = append(s, '\xA8') + case 'P': // PS (#x2029) + s = append(s, '\xE2') + s = append(s, '\x80') + s = append(s, '\xA9') + case 'x': + code_length = 2 + case 'u': + code_length = 4 + case 'U': + code_length = 8 + default: + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "found unknown escape character") + return false + } + + skip(parser) + skip(parser) + + // Consume an arbitrary escape code. + if code_length > 0 { + var value int + + // Scan the character value. + if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) { + return false + } + for k := 0; k < code_length; k++ { + if !is_hex(parser.buffer, parser.buffer_pos+k) { + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "did not find expected hexdecimal number") + return false + } + value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k) + } + + // Check the value and write the character. + if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF { + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "found invalid Unicode character escape code") + return false + } + if value <= 0x7F { + s = append(s, byte(value)) + } else if value <= 0x7FF { + s = append(s, byte(0xC0+(value>>6))) + s = append(s, byte(0x80+(value&0x3F))) + } else if value <= 0xFFFF { + s = append(s, byte(0xE0+(value>>12))) + s = append(s, byte(0x80+((value>>6)&0x3F))) + s = append(s, byte(0x80+(value&0x3F))) + } else { + s = append(s, byte(0xF0+(value>>18))) + s = append(s, byte(0x80+((value>>12)&0x3F))) + s = append(s, byte(0x80+((value>>6)&0x3F))) + s = append(s, byte(0x80+(value&0x3F))) + } + + // Advance the pointer. + for k := 0; k < code_length; k++ { + skip(parser) + } + } + } else { + // It is a non-escaped non-blank character. + s = read(parser, s) + } + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + } + + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + // Check if we are at the end of the scalar. + if single { + if parser.buffer[parser.buffer_pos] == '\'' { + break + } + } else { + if parser.buffer[parser.buffer_pos] == '"' { + break + } + } + + // Consume blank characters. + for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { + if is_blank(parser.buffer, parser.buffer_pos) { + // Consume a space or a tab character. + if !leading_blanks { + whitespaces = read(parser, whitespaces) + } else { + skip(parser) + } + } else { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + + // Check if it is a first line break. + if !leading_blanks { + whitespaces = whitespaces[:0] + leading_break = read_line(parser, leading_break) + leading_blanks = true + } else { + trailing_breaks = read_line(parser, trailing_breaks) + } + } + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Join the whitespaces or fold line breaks. + if leading_blanks { + // Do we need to fold line breaks? + if len(leading_break) > 0 && leading_break[0] == '\n' { + if len(trailing_breaks) == 0 { + s = append(s, ' ') + } else { + s = append(s, trailing_breaks...) + } + } else { + s = append(s, leading_break...) + s = append(s, trailing_breaks...) + } + trailing_breaks = trailing_breaks[:0] + leading_break = leading_break[:0] + } else { + s = append(s, whitespaces...) + whitespaces = whitespaces[:0] + } + } + + // Eat the right quote. + skip(parser) + end_mark := parser.mark + + // Create a token. + *token = yaml_token_t{ + typ: yaml_SCALAR_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: s, + style: yaml_SINGLE_QUOTED_SCALAR_STYLE, + } + if !single { + token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + return true +} + +// Scan a plain scalar. +func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool { + + var s, leading_break, trailing_breaks, whitespaces []byte + var leading_blanks bool + var indent = parser.indent + 1 + + start_mark := parser.mark + end_mark := parser.mark + + // Consume the content of the plain scalar. + for { + // Check for a document indicator. + if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { + return false + } + if parser.mark.column == 0 && + ((parser.buffer[parser.buffer_pos+0] == '-' && + parser.buffer[parser.buffer_pos+1] == '-' && + parser.buffer[parser.buffer_pos+2] == '-') || + (parser.buffer[parser.buffer_pos+0] == '.' && + parser.buffer[parser.buffer_pos+1] == '.' && + parser.buffer[parser.buffer_pos+2] == '.')) && + is_blankz(parser.buffer, parser.buffer_pos+3) { + break + } + + // Check for a comment. + if parser.buffer[parser.buffer_pos] == '#' { + break + } + + // Consume non-blank characters. + for !is_blankz(parser.buffer, parser.buffer_pos) { + + // Check for indicators that may end a plain scalar. + if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) || + (parser.flow_level > 0 && + (parser.buffer[parser.buffer_pos] == ',' || + parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' || + parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || + parser.buffer[parser.buffer_pos] == '}')) { + break + } + + // Check if we need to join whitespaces and breaks. + if leading_blanks || len(whitespaces) > 0 { + if leading_blanks { + // Do we need to fold line breaks? + if leading_break[0] == '\n' { + if len(trailing_breaks) == 0 { + s = append(s, ' ') + } else { + s = append(s, trailing_breaks...) + } + } else { + s = append(s, leading_break...) + s = append(s, trailing_breaks...) + } + trailing_breaks = trailing_breaks[:0] + leading_break = leading_break[:0] + leading_blanks = false + } else { + s = append(s, whitespaces...) + whitespaces = whitespaces[:0] + } + } + + // Copy the character. + s = read(parser, s) + + end_mark = parser.mark + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + } + + // Is it the end? + if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) { + break + } + + // Consume blank characters. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { + if is_blank(parser.buffer, parser.buffer_pos) { + + // Check for tab characters that abuse indentation. + if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", + start_mark, "found a tab character that violates indentation") + return false + } + + // Consume a space or a tab character. + if !leading_blanks { + whitespaces = read(parser, whitespaces) + } else { + skip(parser) + } + } else { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + + // Check if it is a first line break. + if !leading_blanks { + whitespaces = whitespaces[:0] + leading_break = read_line(parser, leading_break) + leading_blanks = true + } else { + trailing_breaks = read_line(parser, trailing_breaks) + } + } + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check indentation level. + if parser.flow_level == 0 && parser.mark.column < indent { + break + } + } + + // Create a token. + *token = yaml_token_t{ + typ: yaml_SCALAR_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: s, + style: yaml_PLAIN_SCALAR_STYLE, + } + + // Note that we change the 'simple_key_allowed' flag. + if leading_blanks { + parser.simple_key_allowed = true + } + return true +} diff --git a/vendor/gopkg.in/yaml.v2/sorter.go b/vendor/gopkg.in/yaml.v2/sorter.go new file mode 100644 index 0000000..4c45e66 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/sorter.go @@ -0,0 +1,113 @@ +package yaml + +import ( + "reflect" + "unicode" +) + +type keyList []reflect.Value + +func (l keyList) Len() int { return len(l) } +func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l keyList) Less(i, j int) bool { + a := l[i] + b := l[j] + ak := a.Kind() + bk := b.Kind() + for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { + a = a.Elem() + ak = a.Kind() + } + for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { + b = b.Elem() + bk = b.Kind() + } + af, aok := keyFloat(a) + bf, bok := keyFloat(b) + if aok && bok { + if af != bf { + return af < bf + } + if ak != bk { + return ak < bk + } + return numLess(a, b) + } + if ak != reflect.String || bk != reflect.String { + return ak < bk + } + ar, br := []rune(a.String()), []rune(b.String()) + for i := 0; i < len(ar) && i < len(br); i++ { + if ar[i] == br[i] { + continue + } + al := unicode.IsLetter(ar[i]) + bl := unicode.IsLetter(br[i]) + if al && bl { + return ar[i] < br[i] + } + if al || bl { + return bl + } + var ai, bi int + var an, bn int64 + if ar[i] == '0' || br[i] == '0' { + for j := i-1; j >= 0 && unicode.IsDigit(ar[j]); j-- { + if ar[j] != '0' { + an = 1 + bn = 1 + break + } + } + } + for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { + an = an*10 + int64(ar[ai]-'0') + } + for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { + bn = bn*10 + int64(br[bi]-'0') + } + if an != bn { + return an < bn + } + if ai != bi { + return ai < bi + } + return ar[i] < br[i] + } + return len(ar) < len(br) +} + +// keyFloat returns a float value for v if it is a number/bool +// and whether it is a number/bool or not. +func keyFloat(v reflect.Value) (f float64, ok bool) { + switch v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return float64(v.Int()), true + case reflect.Float32, reflect.Float64: + return v.Float(), true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return float64(v.Uint()), true + case reflect.Bool: + if v.Bool() { + return 1, true + } + return 0, true + } + return 0, false +} + +// numLess returns whether a < b. +// a and b must necessarily have the same kind. +func numLess(a, b reflect.Value) bool { + switch a.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return a.Int() < b.Int() + case reflect.Float32, reflect.Float64: + return a.Float() < b.Float() + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return a.Uint() < b.Uint() + case reflect.Bool: + return !a.Bool() && b.Bool() + } + panic("not a number") +} diff --git a/vendor/gopkg.in/yaml.v2/writerc.go b/vendor/gopkg.in/yaml.v2/writerc.go new file mode 100644 index 0000000..a2dde60 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/writerc.go @@ -0,0 +1,26 @@ +package yaml + +// Set the writer error and return false. +func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { + emitter.error = yaml_WRITER_ERROR + emitter.problem = problem + return false +} + +// Flush the output buffer. +func yaml_emitter_flush(emitter *yaml_emitter_t) bool { + if emitter.write_handler == nil { + panic("write handler not set") + } + + // Check if the buffer is empty. + if emitter.buffer_pos == 0 { + return true + } + + if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { + return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) + } + emitter.buffer_pos = 0 + return true +} diff --git a/vendor/gopkg.in/yaml.v2/yaml.go b/vendor/gopkg.in/yaml.v2/yaml.go new file mode 100644 index 0000000..89650e2 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/yaml.go @@ -0,0 +1,466 @@ +// Package yaml implements YAML support for the Go language. +// +// Source code and other details for the project are available at GitHub: +// +// https://github.com/go-yaml/yaml +// +package yaml + +import ( + "errors" + "fmt" + "io" + "reflect" + "strings" + "sync" +) + +// MapSlice encodes and decodes as a YAML map. +// The order of keys is preserved when encoding and decoding. +type MapSlice []MapItem + +// MapItem is an item in a MapSlice. +type MapItem struct { + Key, Value interface{} +} + +// The Unmarshaler interface may be implemented by types to customize their +// behavior when being unmarshaled from a YAML document. The UnmarshalYAML +// method receives a function that may be called to unmarshal the original +// YAML value into a field or variable. It is safe to call the unmarshal +// function parameter more than once if necessary. +type Unmarshaler interface { + UnmarshalYAML(unmarshal func(interface{}) error) error +} + +// The Marshaler interface may be implemented by types to customize their +// behavior when being marshaled into a YAML document. The returned value +// is marshaled in place of the original value implementing Marshaler. +// +// If an error is returned by MarshalYAML, the marshaling procedure stops +// and returns with the provided error. +type Marshaler interface { + MarshalYAML() (interface{}, error) +} + +// Unmarshal decodes the first document found within the in byte slice +// and assigns decoded values into the out value. +// +// Maps and pointers (to a struct, string, int, etc) are accepted as out +// values. If an internal pointer within a struct is not initialized, +// the yaml package will initialize it if necessary for unmarshalling +// the provided data. The out parameter must not be nil. +// +// The type of the decoded values should be compatible with the respective +// values in out. If one or more values cannot be decoded due to a type +// mismatches, decoding continues partially until the end of the YAML +// content, and a *yaml.TypeError is returned with details for all +// missed values. +// +// Struct fields are only unmarshalled if they are exported (have an +// upper case first letter), and are unmarshalled using the field name +// lowercased as the default key. Custom keys may be defined via the +// "yaml" name in the field tag: the content preceding the first comma +// is used as the key, and the following comma-separated options are +// used to tweak the marshalling process (see Marshal). +// Conflicting names result in a runtime error. +// +// For example: +// +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// var t T +// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) +// +// See the documentation of Marshal for the format of tags and a list of +// supported tag options. +// +func Unmarshal(in []byte, out interface{}) (err error) { + return unmarshal(in, out, false) +} + +// UnmarshalStrict is like Unmarshal except that any fields that are found +// in the data that do not have corresponding struct members, or mapping +// keys that are duplicates, will result in +// an error. +func UnmarshalStrict(in []byte, out interface{}) (err error) { + return unmarshal(in, out, true) +} + +// A Decoder reads and decodes YAML values from an input stream. +type Decoder struct { + strict bool + parser *parser +} + +// NewDecoder returns a new decoder that reads from r. +// +// The decoder introduces its own buffering and may read +// data from r beyond the YAML values requested. +func NewDecoder(r io.Reader) *Decoder { + return &Decoder{ + parser: newParserFromReader(r), + } +} + +// SetStrict sets whether strict decoding behaviour is enabled when +// decoding items in the data (see UnmarshalStrict). By default, decoding is not strict. +func (dec *Decoder) SetStrict(strict bool) { + dec.strict = strict +} + +// Decode reads the next YAML-encoded value from its input +// and stores it in the value pointed to by v. +// +// See the documentation for Unmarshal for details about the +// conversion of YAML into a Go value. +func (dec *Decoder) Decode(v interface{}) (err error) { + d := newDecoder(dec.strict) + defer handleErr(&err) + node := dec.parser.parse() + if node == nil { + return io.EOF + } + out := reflect.ValueOf(v) + if out.Kind() == reflect.Ptr && !out.IsNil() { + out = out.Elem() + } + d.unmarshal(node, out) + if len(d.terrors) > 0 { + return &TypeError{d.terrors} + } + return nil +} + +func unmarshal(in []byte, out interface{}, strict bool) (err error) { + defer handleErr(&err) + d := newDecoder(strict) + p := newParser(in) + defer p.destroy() + node := p.parse() + if node != nil { + v := reflect.ValueOf(out) + if v.Kind() == reflect.Ptr && !v.IsNil() { + v = v.Elem() + } + d.unmarshal(node, v) + } + if len(d.terrors) > 0 { + return &TypeError{d.terrors} + } + return nil +} + +// Marshal serializes the value provided into a YAML document. The structure +// of the generated document will reflect the structure of the value itself. +// Maps and pointers (to struct, string, int, etc) are accepted as the in value. +// +// Struct fields are only marshalled if they are exported (have an upper case +// first letter), and are marshalled using the field name lowercased as the +// default key. Custom keys may be defined via the "yaml" name in the field +// tag: the content preceding the first comma is used as the key, and the +// following comma-separated options are used to tweak the marshalling process. +// Conflicting names result in a runtime error. +// +// The field tag format accepted is: +// +// `(...) yaml:"[][,[,]]" (...)` +// +// The following flags are currently supported: +// +// omitempty Only include the field if it's not set to the zero +// value for the type or to empty slices or maps. +// Zero valued structs will be omitted if all their public +// fields are zero, unless they implement an IsZero +// method (see the IsZeroer interface type), in which +// case the field will be included if that method returns true. +// +// flow Marshal using a flow style (useful for structs, +// sequences and maps). +// +// inline Inline the field, which must be a struct or a map, +// causing all of its fields or keys to be processed as if +// they were part of the outer struct. For maps, keys must +// not conflict with the yaml keys of other struct fields. +// +// In addition, if the key is "-", the field is ignored. +// +// For example: +// +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" +// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" +// +func Marshal(in interface{}) (out []byte, err error) { + defer handleErr(&err) + e := newEncoder() + defer e.destroy() + e.marshalDoc("", reflect.ValueOf(in)) + e.finish() + out = e.out + return +} + +// An Encoder writes YAML values to an output stream. +type Encoder struct { + encoder *encoder +} + +// NewEncoder returns a new encoder that writes to w. +// The Encoder should be closed after use to flush all data +// to w. +func NewEncoder(w io.Writer) *Encoder { + return &Encoder{ + encoder: newEncoderWithWriter(w), + } +} + +// Encode writes the YAML encoding of v to the stream. +// If multiple items are encoded to the stream, the +// second and subsequent document will be preceded +// with a "---" document separator, but the first will not. +// +// See the documentation for Marshal for details about the conversion of Go +// values to YAML. +func (e *Encoder) Encode(v interface{}) (err error) { + defer handleErr(&err) + e.encoder.marshalDoc("", reflect.ValueOf(v)) + return nil +} + +// Close closes the encoder by writing any remaining data. +// It does not write a stream terminating string "...". +func (e *Encoder) Close() (err error) { + defer handleErr(&err) + e.encoder.finish() + return nil +} + +func handleErr(err *error) { + if v := recover(); v != nil { + if e, ok := v.(yamlError); ok { + *err = e.err + } else { + panic(v) + } + } +} + +type yamlError struct { + err error +} + +func fail(err error) { + panic(yamlError{err}) +} + +func failf(format string, args ...interface{}) { + panic(yamlError{fmt.Errorf("yaml: "+format, args...)}) +} + +// A TypeError is returned by Unmarshal when one or more fields in +// the YAML document cannot be properly decoded into the requested +// types. When this error is returned, the value is still +// unmarshaled partially. +type TypeError struct { + Errors []string +} + +func (e *TypeError) Error() string { + return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n ")) +} + +// -------------------------------------------------------------------------- +// Maintain a mapping of keys to structure field indexes + +// The code in this section was copied from mgo/bson. + +// structInfo holds details for the serialization of fields of +// a given struct. +type structInfo struct { + FieldsMap map[string]fieldInfo + FieldsList []fieldInfo + + // InlineMap is the number of the field in the struct that + // contains an ,inline map, or -1 if there's none. + InlineMap int +} + +type fieldInfo struct { + Key string + Num int + OmitEmpty bool + Flow bool + // Id holds the unique field identifier, so we can cheaply + // check for field duplicates without maintaining an extra map. + Id int + + // Inline holds the field index if the field is part of an inlined struct. + Inline []int +} + +var structMap = make(map[reflect.Type]*structInfo) +var fieldMapMutex sync.RWMutex + +func getStructInfo(st reflect.Type) (*structInfo, error) { + fieldMapMutex.RLock() + sinfo, found := structMap[st] + fieldMapMutex.RUnlock() + if found { + return sinfo, nil + } + + n := st.NumField() + fieldsMap := make(map[string]fieldInfo) + fieldsList := make([]fieldInfo, 0, n) + inlineMap := -1 + for i := 0; i != n; i++ { + field := st.Field(i) + if field.PkgPath != "" && !field.Anonymous { + continue // Private field + } + + info := fieldInfo{Num: i} + + tag := field.Tag.Get("yaml") + if tag == "" && strings.Index(string(field.Tag), ":") < 0 { + tag = string(field.Tag) + } + if tag == "-" { + continue + } + + inline := false + fields := strings.Split(tag, ",") + if len(fields) > 1 { + for _, flag := range fields[1:] { + switch flag { + case "omitempty": + info.OmitEmpty = true + case "flow": + info.Flow = true + case "inline": + inline = true + default: + return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)) + } + } + tag = fields[0] + } + + if inline { + switch field.Type.Kind() { + case reflect.Map: + if inlineMap >= 0 { + return nil, errors.New("Multiple ,inline maps in struct " + st.String()) + } + if field.Type.Key() != reflect.TypeOf("") { + return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String()) + } + inlineMap = info.Num + case reflect.Struct: + sinfo, err := getStructInfo(field.Type) + if err != nil { + return nil, err + } + for _, finfo := range sinfo.FieldsList { + if _, found := fieldsMap[finfo.Key]; found { + msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String() + return nil, errors.New(msg) + } + if finfo.Inline == nil { + finfo.Inline = []int{i, finfo.Num} + } else { + finfo.Inline = append([]int{i}, finfo.Inline...) + } + finfo.Id = len(fieldsList) + fieldsMap[finfo.Key] = finfo + fieldsList = append(fieldsList, finfo) + } + default: + //return nil, errors.New("Option ,inline needs a struct value or map field") + return nil, errors.New("Option ,inline needs a struct value field") + } + continue + } + + if tag != "" { + info.Key = tag + } else { + info.Key = strings.ToLower(field.Name) + } + + if _, found = fieldsMap[info.Key]; found { + msg := "Duplicated key '" + info.Key + "' in struct " + st.String() + return nil, errors.New(msg) + } + + info.Id = len(fieldsList) + fieldsList = append(fieldsList, info) + fieldsMap[info.Key] = info + } + + sinfo = &structInfo{ + FieldsMap: fieldsMap, + FieldsList: fieldsList, + InlineMap: inlineMap, + } + + fieldMapMutex.Lock() + structMap[st] = sinfo + fieldMapMutex.Unlock() + return sinfo, nil +} + +// IsZeroer is used to check whether an object is zero to +// determine whether it should be omitted when marshaling +// with the omitempty flag. One notable implementation +// is time.Time. +type IsZeroer interface { + IsZero() bool +} + +func isZero(v reflect.Value) bool { + kind := v.Kind() + if z, ok := v.Interface().(IsZeroer); ok { + if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() { + return true + } + return z.IsZero() + } + switch kind { + case reflect.String: + return len(v.String()) == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + case reflect.Slice: + return v.Len() == 0 + case reflect.Map: + return v.Len() == 0 + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Struct: + vt := v.Type() + for i := v.NumField() - 1; i >= 0; i-- { + if vt.Field(i).PkgPath != "" { + continue // Private field + } + if !isZero(v.Field(i)) { + return false + } + } + return true + } + return false +} diff --git a/vendor/gopkg.in/yaml.v2/yamlh.go b/vendor/gopkg.in/yaml.v2/yamlh.go new file mode 100644 index 0000000..f6a9c8e --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/yamlh.go @@ -0,0 +1,739 @@ +package yaml + +import ( + "fmt" + "io" +) + +// The version directive data. +type yaml_version_directive_t struct { + major int8 // The major version number. + minor int8 // The minor version number. +} + +// The tag directive data. +type yaml_tag_directive_t struct { + handle []byte // The tag handle. + prefix []byte // The tag prefix. +} + +type yaml_encoding_t int + +// The stream encoding. +const ( + // Let the parser choose the encoding. + yaml_ANY_ENCODING yaml_encoding_t = iota + + yaml_UTF8_ENCODING // The default UTF-8 encoding. + yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM. + yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM. +) + +type yaml_break_t int + +// Line break types. +const ( + // Let the parser choose the break type. + yaml_ANY_BREAK yaml_break_t = iota + + yaml_CR_BREAK // Use CR for line breaks (Mac style). + yaml_LN_BREAK // Use LN for line breaks (Unix style). + yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style). +) + +type yaml_error_type_t int + +// Many bad things could happen with the parser and emitter. +const ( + // No error is produced. + yaml_NO_ERROR yaml_error_type_t = iota + + yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory. + yaml_READER_ERROR // Cannot read or decode the input stream. + yaml_SCANNER_ERROR // Cannot scan the input stream. + yaml_PARSER_ERROR // Cannot parse the input stream. + yaml_COMPOSER_ERROR // Cannot compose a YAML document. + yaml_WRITER_ERROR // Cannot write to the output stream. + yaml_EMITTER_ERROR // Cannot emit a YAML stream. +) + +// The pointer position. +type yaml_mark_t struct { + index int // The position index. + line int // The position line. + column int // The position column. +} + +// Node Styles + +type yaml_style_t int8 + +type yaml_scalar_style_t yaml_style_t + +// Scalar styles. +const ( + // Let the emitter choose the style. + yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota + + yaml_PLAIN_SCALAR_STYLE // The plain scalar style. + yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style. + yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style. + yaml_LITERAL_SCALAR_STYLE // The literal scalar style. + yaml_FOLDED_SCALAR_STYLE // The folded scalar style. +) + +type yaml_sequence_style_t yaml_style_t + +// Sequence styles. +const ( + // Let the emitter choose the style. + yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota + + yaml_BLOCK_SEQUENCE_STYLE // The block sequence style. + yaml_FLOW_SEQUENCE_STYLE // The flow sequence style. +) + +type yaml_mapping_style_t yaml_style_t + +// Mapping styles. +const ( + // Let the emitter choose the style. + yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota + + yaml_BLOCK_MAPPING_STYLE // The block mapping style. + yaml_FLOW_MAPPING_STYLE // The flow mapping style. +) + +// Tokens + +type yaml_token_type_t int + +// Token types. +const ( + // An empty token. + yaml_NO_TOKEN yaml_token_type_t = iota + + yaml_STREAM_START_TOKEN // A STREAM-START token. + yaml_STREAM_END_TOKEN // A STREAM-END token. + + yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token. + yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token. + yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token. + yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token. + + yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token. + yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token. + yaml_BLOCK_END_TOKEN // A BLOCK-END token. + + yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token. + yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token. + yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token. + yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token. + + yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token. + yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token. + yaml_KEY_TOKEN // A KEY token. + yaml_VALUE_TOKEN // A VALUE token. + + yaml_ALIAS_TOKEN // An ALIAS token. + yaml_ANCHOR_TOKEN // An ANCHOR token. + yaml_TAG_TOKEN // A TAG token. + yaml_SCALAR_TOKEN // A SCALAR token. +) + +func (tt yaml_token_type_t) String() string { + switch tt { + case yaml_NO_TOKEN: + return "yaml_NO_TOKEN" + case yaml_STREAM_START_TOKEN: + return "yaml_STREAM_START_TOKEN" + case yaml_STREAM_END_TOKEN: + return "yaml_STREAM_END_TOKEN" + case yaml_VERSION_DIRECTIVE_TOKEN: + return "yaml_VERSION_DIRECTIVE_TOKEN" + case yaml_TAG_DIRECTIVE_TOKEN: + return "yaml_TAG_DIRECTIVE_TOKEN" + case yaml_DOCUMENT_START_TOKEN: + return "yaml_DOCUMENT_START_TOKEN" + case yaml_DOCUMENT_END_TOKEN: + return "yaml_DOCUMENT_END_TOKEN" + case yaml_BLOCK_SEQUENCE_START_TOKEN: + return "yaml_BLOCK_SEQUENCE_START_TOKEN" + case yaml_BLOCK_MAPPING_START_TOKEN: + return "yaml_BLOCK_MAPPING_START_TOKEN" + case yaml_BLOCK_END_TOKEN: + return "yaml_BLOCK_END_TOKEN" + case yaml_FLOW_SEQUENCE_START_TOKEN: + return "yaml_FLOW_SEQUENCE_START_TOKEN" + case yaml_FLOW_SEQUENCE_END_TOKEN: + return "yaml_FLOW_SEQUENCE_END_TOKEN" + case yaml_FLOW_MAPPING_START_TOKEN: + return "yaml_FLOW_MAPPING_START_TOKEN" + case yaml_FLOW_MAPPING_END_TOKEN: + return "yaml_FLOW_MAPPING_END_TOKEN" + case yaml_BLOCK_ENTRY_TOKEN: + return "yaml_BLOCK_ENTRY_TOKEN" + case yaml_FLOW_ENTRY_TOKEN: + return "yaml_FLOW_ENTRY_TOKEN" + case yaml_KEY_TOKEN: + return "yaml_KEY_TOKEN" + case yaml_VALUE_TOKEN: + return "yaml_VALUE_TOKEN" + case yaml_ALIAS_TOKEN: + return "yaml_ALIAS_TOKEN" + case yaml_ANCHOR_TOKEN: + return "yaml_ANCHOR_TOKEN" + case yaml_TAG_TOKEN: + return "yaml_TAG_TOKEN" + case yaml_SCALAR_TOKEN: + return "yaml_SCALAR_TOKEN" + } + return "" +} + +// The token structure. +type yaml_token_t struct { + // The token type. + typ yaml_token_type_t + + // The start/end of the token. + start_mark, end_mark yaml_mark_t + + // The stream encoding (for yaml_STREAM_START_TOKEN). + encoding yaml_encoding_t + + // The alias/anchor/scalar value or tag/tag directive handle + // (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN). + value []byte + + // The tag suffix (for yaml_TAG_TOKEN). + suffix []byte + + // The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN). + prefix []byte + + // The scalar style (for yaml_SCALAR_TOKEN). + style yaml_scalar_style_t + + // The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN). + major, minor int8 +} + +// Events + +type yaml_event_type_t int8 + +// Event types. +const ( + // An empty event. + yaml_NO_EVENT yaml_event_type_t = iota + + yaml_STREAM_START_EVENT // A STREAM-START event. + yaml_STREAM_END_EVENT // A STREAM-END event. + yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event. + yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event. + yaml_ALIAS_EVENT // An ALIAS event. + yaml_SCALAR_EVENT // A SCALAR event. + yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event. + yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event. + yaml_MAPPING_START_EVENT // A MAPPING-START event. + yaml_MAPPING_END_EVENT // A MAPPING-END event. +) + +var eventStrings = []string{ + yaml_NO_EVENT: "none", + yaml_STREAM_START_EVENT: "stream start", + yaml_STREAM_END_EVENT: "stream end", + yaml_DOCUMENT_START_EVENT: "document start", + yaml_DOCUMENT_END_EVENT: "document end", + yaml_ALIAS_EVENT: "alias", + yaml_SCALAR_EVENT: "scalar", + yaml_SEQUENCE_START_EVENT: "sequence start", + yaml_SEQUENCE_END_EVENT: "sequence end", + yaml_MAPPING_START_EVENT: "mapping start", + yaml_MAPPING_END_EVENT: "mapping end", +} + +func (e yaml_event_type_t) String() string { + if e < 0 || int(e) >= len(eventStrings) { + return fmt.Sprintf("unknown event %d", e) + } + return eventStrings[e] +} + +// The event structure. +type yaml_event_t struct { + + // The event type. + typ yaml_event_type_t + + // The start and end of the event. + start_mark, end_mark yaml_mark_t + + // The document encoding (for yaml_STREAM_START_EVENT). + encoding yaml_encoding_t + + // The version directive (for yaml_DOCUMENT_START_EVENT). + version_directive *yaml_version_directive_t + + // The list of tag directives (for yaml_DOCUMENT_START_EVENT). + tag_directives []yaml_tag_directive_t + + // The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT). + anchor []byte + + // The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). + tag []byte + + // The scalar value (for yaml_SCALAR_EVENT). + value []byte + + // Is the document start/end indicator implicit, or the tag optional? + // (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT). + implicit bool + + // Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT). + quoted_implicit bool + + // The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). + style yaml_style_t +} + +func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) } +func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) } +func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) } + +// Nodes + +const ( + yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null. + yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false. + yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values. + yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values. + yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values. + yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values. + + yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences. + yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping. + + // Not in original libyaml. + yaml_BINARY_TAG = "tag:yaml.org,2002:binary" + yaml_MERGE_TAG = "tag:yaml.org,2002:merge" + + yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str. + yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq. + yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map. +) + +type yaml_node_type_t int + +// Node types. +const ( + // An empty node. + yaml_NO_NODE yaml_node_type_t = iota + + yaml_SCALAR_NODE // A scalar node. + yaml_SEQUENCE_NODE // A sequence node. + yaml_MAPPING_NODE // A mapping node. +) + +// An element of a sequence node. +type yaml_node_item_t int + +// An element of a mapping node. +type yaml_node_pair_t struct { + key int // The key of the element. + value int // The value of the element. +} + +// The node structure. +type yaml_node_t struct { + typ yaml_node_type_t // The node type. + tag []byte // The node tag. + + // The node data. + + // The scalar parameters (for yaml_SCALAR_NODE). + scalar struct { + value []byte // The scalar value. + length int // The length of the scalar value. + style yaml_scalar_style_t // The scalar style. + } + + // The sequence parameters (for YAML_SEQUENCE_NODE). + sequence struct { + items_data []yaml_node_item_t // The stack of sequence items. + style yaml_sequence_style_t // The sequence style. + } + + // The mapping parameters (for yaml_MAPPING_NODE). + mapping struct { + pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value). + pairs_start *yaml_node_pair_t // The beginning of the stack. + pairs_end *yaml_node_pair_t // The end of the stack. + pairs_top *yaml_node_pair_t // The top of the stack. + style yaml_mapping_style_t // The mapping style. + } + + start_mark yaml_mark_t // The beginning of the node. + end_mark yaml_mark_t // The end of the node. + +} + +// The document structure. +type yaml_document_t struct { + + // The document nodes. + nodes []yaml_node_t + + // The version directive. + version_directive *yaml_version_directive_t + + // The list of tag directives. + tag_directives_data []yaml_tag_directive_t + tag_directives_start int // The beginning of the tag directives list. + tag_directives_end int // The end of the tag directives list. + + start_implicit int // Is the document start indicator implicit? + end_implicit int // Is the document end indicator implicit? + + // The start/end of the document. + start_mark, end_mark yaml_mark_t +} + +// The prototype of a read handler. +// +// The read handler is called when the parser needs to read more bytes from the +// source. The handler should write not more than size bytes to the buffer. +// The number of written bytes should be set to the size_read variable. +// +// [in,out] data A pointer to an application data specified by +// yaml_parser_set_input(). +// [out] buffer The buffer to write the data from the source. +// [in] size The size of the buffer. +// [out] size_read The actual number of bytes read from the source. +// +// On success, the handler should return 1. If the handler failed, +// the returned value should be 0. On EOF, the handler should set the +// size_read to 0 and return 1. +type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error) + +// This structure holds information about a potential simple key. +type yaml_simple_key_t struct { + possible bool // Is a simple key possible? + required bool // Is a simple key required? + token_number int // The number of the token. + mark yaml_mark_t // The position mark. +} + +// The states of the parser. +type yaml_parser_state_t int + +const ( + yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota + + yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document. + yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START. + yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document. + yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END. + yaml_PARSE_BLOCK_NODE_STATE // Expect a block node. + yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence. + yaml_PARSE_FLOW_NODE_STATE // Expect a flow node. + yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence. + yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence. + yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence. + yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. + yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key. + yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value. + yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence. + yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence. + yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping. + yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping. + yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry. + yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. + yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. + yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. + yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping. + yaml_PARSE_END_STATE // Expect nothing. +) + +func (ps yaml_parser_state_t) String() string { + switch ps { + case yaml_PARSE_STREAM_START_STATE: + return "yaml_PARSE_STREAM_START_STATE" + case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: + return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE" + case yaml_PARSE_DOCUMENT_START_STATE: + return "yaml_PARSE_DOCUMENT_START_STATE" + case yaml_PARSE_DOCUMENT_CONTENT_STATE: + return "yaml_PARSE_DOCUMENT_CONTENT_STATE" + case yaml_PARSE_DOCUMENT_END_STATE: + return "yaml_PARSE_DOCUMENT_END_STATE" + case yaml_PARSE_BLOCK_NODE_STATE: + return "yaml_PARSE_BLOCK_NODE_STATE" + case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: + return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE" + case yaml_PARSE_FLOW_NODE_STATE: + return "yaml_PARSE_FLOW_NODE_STATE" + case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: + return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE" + case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: + return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE" + case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: + return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE" + case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: + return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE" + case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: + return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE" + case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: + return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE" + case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE" + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE" + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE" + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE" + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE" + case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: + return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE" + case yaml_PARSE_FLOW_MAPPING_KEY_STATE: + return "yaml_PARSE_FLOW_MAPPING_KEY_STATE" + case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: + return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE" + case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: + return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE" + case yaml_PARSE_END_STATE: + return "yaml_PARSE_END_STATE" + } + return "" +} + +// This structure holds aliases data. +type yaml_alias_data_t struct { + anchor []byte // The anchor. + index int // The node id. + mark yaml_mark_t // The anchor mark. +} + +// The parser structure. +// +// All members are internal. Manage the structure using the +// yaml_parser_ family of functions. +type yaml_parser_t struct { + + // Error handling + + error yaml_error_type_t // Error type. + + problem string // Error description. + + // The byte about which the problem occurred. + problem_offset int + problem_value int + problem_mark yaml_mark_t + + // The error context. + context string + context_mark yaml_mark_t + + // Reader stuff + + read_handler yaml_read_handler_t // Read handler. + + input_reader io.Reader // File input data. + input []byte // String input data. + input_pos int + + eof bool // EOF flag + + buffer []byte // The working buffer. + buffer_pos int // The current position of the buffer. + + unread int // The number of unread characters in the buffer. + + raw_buffer []byte // The raw buffer. + raw_buffer_pos int // The current position of the buffer. + + encoding yaml_encoding_t // The input encoding. + + offset int // The offset of the current position (in bytes). + mark yaml_mark_t // The mark of the current position. + + // Scanner stuff + + stream_start_produced bool // Have we started to scan the input stream? + stream_end_produced bool // Have we reached the end of the input stream? + + flow_level int // The number of unclosed '[' and '{' indicators. + + tokens []yaml_token_t // The tokens queue. + tokens_head int // The head of the tokens queue. + tokens_parsed int // The number of tokens fetched from the queue. + token_available bool // Does the tokens queue contain a token ready for dequeueing. + + indent int // The current indentation level. + indents []int // The indentation levels stack. + + simple_key_allowed bool // May a simple key occur at the current position? + simple_keys []yaml_simple_key_t // The stack of simple keys. + simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number + + // Parser stuff + + state yaml_parser_state_t // The current parser state. + states []yaml_parser_state_t // The parser states stack. + marks []yaml_mark_t // The stack of marks. + tag_directives []yaml_tag_directive_t // The list of TAG directives. + + // Dumper stuff + + aliases []yaml_alias_data_t // The alias data. + + document *yaml_document_t // The currently parsed document. +} + +// Emitter Definitions + +// The prototype of a write handler. +// +// The write handler is called when the emitter needs to flush the accumulated +// characters to the output. The handler should write @a size bytes of the +// @a buffer to the output. +// +// @param[in,out] data A pointer to an application data specified by +// yaml_emitter_set_output(). +// @param[in] buffer The buffer with bytes to be written. +// @param[in] size The size of the buffer. +// +// @returns On success, the handler should return @c 1. If the handler failed, +// the returned value should be @c 0. +// +type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error + +type yaml_emitter_state_t int + +// The emitter states. +const ( + // Expect STREAM-START. + yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota + + yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END. + yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END. + yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document. + yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END. + yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence. + yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence. + yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. + yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. + yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping. + yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. + yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence. + yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence. + yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. + yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping. + yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping. + yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping. + yaml_EMIT_END_STATE // Expect nothing. +) + +// The emitter structure. +// +// All members are internal. Manage the structure using the @c yaml_emitter_ +// family of functions. +type yaml_emitter_t struct { + + // Error handling + + error yaml_error_type_t // Error type. + problem string // Error description. + + // Writer stuff + + write_handler yaml_write_handler_t // Write handler. + + output_buffer *[]byte // String output data. + output_writer io.Writer // File output data. + + buffer []byte // The working buffer. + buffer_pos int // The current position of the buffer. + + raw_buffer []byte // The raw buffer. + raw_buffer_pos int // The current position of the buffer. + + encoding yaml_encoding_t // The stream encoding. + + // Emitter stuff + + canonical bool // If the output is in the canonical style? + best_indent int // The number of indentation spaces. + best_width int // The preferred width of the output lines. + unicode bool // Allow unescaped non-ASCII characters? + line_break yaml_break_t // The preferred line break. + + state yaml_emitter_state_t // The current emitter state. + states []yaml_emitter_state_t // The stack of states. + + events []yaml_event_t // The event queue. + events_head int // The head of the event queue. + + indents []int // The stack of indentation levels. + + tag_directives []yaml_tag_directive_t // The list of tag directives. + + indent int // The current indentation level. + + flow_level int // The current flow level. + + root_context bool // Is it the document root context? + sequence_context bool // Is it a sequence context? + mapping_context bool // Is it a mapping context? + simple_key_context bool // Is it a simple mapping key context? + + line int // The current line. + column int // The current column. + whitespace bool // If the last character was a whitespace? + indention bool // If the last character was an indentation character (' ', '-', '?', ':')? + open_ended bool // If an explicit document end is required? + + // Anchor analysis. + anchor_data struct { + anchor []byte // The anchor value. + alias bool // Is it an alias? + } + + // Tag analysis. + tag_data struct { + handle []byte // The tag handle. + suffix []byte // The tag suffix. + } + + // Scalar analysis. + scalar_data struct { + value []byte // The scalar value. + multiline bool // Does the scalar contain line breaks? + flow_plain_allowed bool // Can the scalar be expessed in the flow plain style? + block_plain_allowed bool // Can the scalar be expressed in the block plain style? + single_quoted_allowed bool // Can the scalar be expressed in the single quoted style? + block_allowed bool // Can the scalar be expressed in the literal or folded styles? + style yaml_scalar_style_t // The output style. + } + + // Dumper stuff + + opened bool // If the stream was already opened? + closed bool // If the stream was already closed? + + // The information associated with the document nodes. + anchors *struct { + references int // The number of references. + anchor int // The anchor id. + serialized bool // If the node has been emitted? + } + + last_anchor_id int // The last assigned anchor id. + + document *yaml_document_t // The currently emitted document. +} diff --git a/vendor/gopkg.in/yaml.v2/yamlprivateh.go b/vendor/gopkg.in/yaml.v2/yamlprivateh.go new file mode 100644 index 0000000..8110ce3 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/yamlprivateh.go @@ -0,0 +1,173 @@ +package yaml + +const ( + // The size of the input raw buffer. + input_raw_buffer_size = 512 + + // The size of the input buffer. + // It should be possible to decode the whole raw buffer. + input_buffer_size = input_raw_buffer_size * 3 + + // The size of the output buffer. + output_buffer_size = 128 + + // The size of the output raw buffer. + // It should be possible to encode the whole output buffer. + output_raw_buffer_size = (output_buffer_size*2 + 2) + + // The size of other stacks and queues. + initial_stack_size = 16 + initial_queue_size = 16 + initial_string_size = 16 +) + +// Check if the character at the specified position is an alphabetical +// character, a digit, '_', or '-'. +func is_alpha(b []byte, i int) bool { + return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' +} + +// Check if the character at the specified position is a digit. +func is_digit(b []byte, i int) bool { + return b[i] >= '0' && b[i] <= '9' +} + +// Get the value of a digit. +func as_digit(b []byte, i int) int { + return int(b[i]) - '0' +} + +// Check if the character at the specified position is a hex-digit. +func is_hex(b []byte, i int) bool { + return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' +} + +// Get the value of a hex-digit. +func as_hex(b []byte, i int) int { + bi := b[i] + if bi >= 'A' && bi <= 'F' { + return int(bi) - 'A' + 10 + } + if bi >= 'a' && bi <= 'f' { + return int(bi) - 'a' + 10 + } + return int(bi) - '0' +} + +// Check if the character is ASCII. +func is_ascii(b []byte, i int) bool { + return b[i] <= 0x7F +} + +// Check if the character at the start of the buffer can be printed unescaped. +func is_printable(b []byte, i int) bool { + return ((b[i] == 0x0A) || // . == #x0A + (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E + (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF + (b[i] > 0xC2 && b[i] < 0xED) || + (b[i] == 0xED && b[i+1] < 0xA0) || + (b[i] == 0xEE) || + (b[i] == 0xEF && // #xE000 <= . <= #xFFFD + !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF + !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) +} + +// Check if the character at the specified position is NUL. +func is_z(b []byte, i int) bool { + return b[i] == 0x00 +} + +// Check if the beginning of the buffer is a BOM. +func is_bom(b []byte, i int) bool { + return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF +} + +// Check if the character at the specified position is space. +func is_space(b []byte, i int) bool { + return b[i] == ' ' +} + +// Check if the character at the specified position is tab. +func is_tab(b []byte, i int) bool { + return b[i] == '\t' +} + +// Check if the character at the specified position is blank (space or tab). +func is_blank(b []byte, i int) bool { + //return is_space(b, i) || is_tab(b, i) + return b[i] == ' ' || b[i] == '\t' +} + +// Check if the character at the specified position is a line break. +func is_break(b []byte, i int) bool { + return (b[i] == '\r' || // CR (#xD) + b[i] == '\n' || // LF (#xA) + b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) +} + +func is_crlf(b []byte, i int) bool { + return b[i] == '\r' && b[i+1] == '\n' +} + +// Check if the character is a line break or NUL. +func is_breakz(b []byte, i int) bool { + //return is_break(b, i) || is_z(b, i) + return ( // is_break: + b[i] == '\r' || // CR (#xD) + b[i] == '\n' || // LF (#xA) + b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) + // is_z: + b[i] == 0) +} + +// Check if the character is a line break, space, or NUL. +func is_spacez(b []byte, i int) bool { + //return is_space(b, i) || is_breakz(b, i) + return ( // is_space: + b[i] == ' ' || + // is_breakz: + b[i] == '\r' || // CR (#xD) + b[i] == '\n' || // LF (#xA) + b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) + b[i] == 0) +} + +// Check if the character is a line break, space, tab, or NUL. +func is_blankz(b []byte, i int) bool { + //return is_blank(b, i) || is_breakz(b, i) + return ( // is_blank: + b[i] == ' ' || b[i] == '\t' || + // is_breakz: + b[i] == '\r' || // CR (#xD) + b[i] == '\n' || // LF (#xA) + b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) + b[i] == 0) +} + +// Determine the width of the character. +func width(b byte) int { + // Don't replace these by a switch without first + // confirming that it is being inlined. + if b&0x80 == 0x00 { + return 1 + } + if b&0xE0 == 0xC0 { + return 2 + } + if b&0xF0 == 0xE0 { + return 3 + } + if b&0xF8 == 0xF0 { + return 4 + } + return 0 + +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 1dbde50..9d858c0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -62,6 +62,10 @@ github.com/decred/dcrd/lru github.com/go-errors/errors # github.com/golang/protobuf v1.4.2 github.com/golang/protobuf/proto +# github.com/hhrutter/lzw v0.0.0-20190829144645-6f07a24e8650 +github.com/hhrutter/lzw +# github.com/hhrutter/tiff v0.0.0-20190829141212-736cae8d0bc7 +github.com/hhrutter/tiff # github.com/jinzhu/gorm v1.9.16 github.com/jinzhu/gorm github.com/jinzhu/gorm/dialects/sqlite @@ -124,11 +128,12 @@ github.com/ltcsuite/ltcd/wire github.com/mattn/go-sqlite3 # github.com/miekg/dns v1.1.29 github.com/miekg/dns -# github.com/muun/libwallet v0.5.0 +# github.com/muun/libwallet v0.7.0 github.com/muun/libwallet github.com/muun/libwallet/addresses github.com/muun/libwallet/aescbc github.com/muun/libwallet/emergencykit +github.com/muun/libwallet/errors github.com/muun/libwallet/fees github.com/muun/libwallet/hdpath github.com/muun/libwallet/keycrypt @@ -136,6 +141,16 @@ github.com/muun/libwallet/recoverycode github.com/muun/libwallet/sphinx github.com/muun/libwallet/swaps github.com/muun/libwallet/walletdb +# github.com/pdfcpu/pdfcpu v0.3.8 +github.com/pdfcpu/pdfcpu/internal/config +github.com/pdfcpu/pdfcpu/internal/corefont/metrics +github.com/pdfcpu/pdfcpu/pkg/api +github.com/pdfcpu/pdfcpu/pkg/filter +github.com/pdfcpu/pdfcpu/pkg/font +github.com/pdfcpu/pdfcpu/pkg/log +github.com/pdfcpu/pdfcpu/pkg/pdfcpu +github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate +github.com/pdfcpu/pdfcpu/pkg/types # github.com/pkg/errors v0.9.1 github.com/pkg/errors # go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50 @@ -151,6 +166,8 @@ golang.org/x/crypto/ripemd160 golang.org/x/crypto/salsa20/salsa golang.org/x/crypto/scrypt golang.org/x/crypto/ssh/terminal +# golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 +golang.org/x/image/ccitt # golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e golang.org/x/net/bpf golang.org/x/net/internal/iana @@ -192,3 +209,5 @@ google.golang.org/protobuf/runtime/protoiface google.golang.org/protobuf/runtime/protoimpl # gopkg.in/gormigrate.v1 v1.6.0 gopkg.in/gormigrate.v1 +# gopkg.in/yaml.v2 v2.3.0 +gopkg.in/yaml.v2