Use UTF-16BE encoding when required

Fix #2
This commit is contained in:
Paul van Brouwershaven
2023-03-10 09:07:27 +01:00
parent 7fd1d3df69
commit 4fb6fafba6
4 changed files with 115 additions and 8 deletions

View File

@@ -11,6 +11,9 @@ import (
"time"
"github.com/digitorus/pdf"
"golang.org/x/text/encoding/unicode"
"golang.org/x/text/transform"
)
func findFirstPage(parent pdf.Value) (pdf.Value, error) {
@@ -35,11 +38,28 @@ func findFirstPage(parent pdf.Value) (pdf.Value, error) {
}
func pdfString(text string) string {
if !isASCII(text) {
// UTF-16BE
enc := unicode.UTF16(unicode.BigEndian, unicode.UseBOM).NewEncoder()
res, _, err := transform.String(enc, text)
if err != nil {
panic(err)
}
return "(" + res + ")"
}
// UTF-8
// (\357\273\277Layer 1) % UTF-8 Layer 1 Name
// <EF BB BF DA AF DA 86 D9 BE DA 98> % UTF-8 Layer 2 Name
// text = "\357\273\277" + text
// text = hex.EncodeToString([]byte(text))
// text = "<" + text + ">"
// PDFDocEncoded
text = strings.Replace(text, "\\", "\\\\", -1)
text = strings.Replace(text, ")", "\\)", -1)
text = strings.Replace(text, "(", "\\(", -1)
text = strings.Replace(text, "\r", "\\r", -1)
text = "(" + text + ")"
return text
@@ -167,3 +187,12 @@ func getOIDFromHashAlgorithm(target crypto.Hash) asn1.ObjectIdentifier {
}
return nil
}
func isASCII(s string) bool {
for _, r := range s {
if r > '\u007F' {
return false
}
}
return true
}

View File

@@ -68,7 +68,7 @@ func TestReaderCanReadPDF(t *testing.T) {
if ext != ".pdf" {
continue
}
fileName := f.Name()
t.Run(fileName, func(st *testing.T) {
st.Parallel()
@@ -285,6 +285,82 @@ func TestSignPDFFile(t *testing.T) {
}
}
func TestSignPDFFileUTF8(t *testing.T) {
certificate_data_block, _ := pem.Decode([]byte(signCertPem))
if certificate_data_block == nil {
t.Errorf("failed to parse PEM block containing the certificate")
return
}
cert, err := x509.ParseCertificate(certificate_data_block.Bytes)
if err != nil {
t.Errorf("%s", err.Error())
return
}
key_data_block, _ := pem.Decode([]byte(signKeyPem))
if key_data_block == nil {
t.Errorf("failed to parse PEM block containing the private key")
return
}
pkey, err := x509.ParsePKCS1PrivateKey(key_data_block.Bytes)
if err != nil {
t.Errorf("%s", err.Error())
return
}
tmpfile, err := os.CreateTemp("", "pdfsign_test")
if err != nil {
t.Errorf("%s", err.Error())
return
}
signerName := "姓名"
signerLocation := "位置"
err = SignFile("../testfiles/testfile20.pdf", tmpfile.Name(), SignData{
Signature: SignDataSignature{
Info: SignDataSignatureInfo{
Name: signerName,
Location: signerLocation,
Reason: "Test with UTF-8",
ContactInfo: "None",
Date: time.Now().Local(),
},
CertType: CertificationSignature,
DocMDPPerm: AllowFillingExistingFormFieldsAndSignaturesPerms,
},
DigestAlgorithm: crypto.SHA512,
Signer: pkey,
Certificate: cert,
})
if err != nil {
os.Remove(tmpfile.Name())
t.Errorf("%s: %s", "testfile20.pdf", err.Error())
return
}
info, err := verify.File(tmpfile)
if err != nil {
t.Errorf("%s: %s", tmpfile.Name(), err.Error())
err2 := os.Rename(tmpfile.Name(), "../testfiles/failed/testfile20.pdf")
if err2 != nil {
t.Error(err2)
}
} else {
if info.Signers[0].Name != signerName {
t.Errorf("expected %q, got %q", signerName, info.Signers[0].Name)
}
if info.Signers[0].Location != signerLocation {
t.Errorf("expected %q, got %q", signerLocation, info.Signers[0].Location)
}
os.Remove(tmpfile.Name())
}
}
func BenchmarkSignPDF(b *testing.B) {
certificate_data_block, _ := pem.Decode([]byte(signCertPem))
if certificate_data_block == nil {