/// <summary> /// Converts the specified byte array into a byte array representing a string literal. /// </summary> /// <param name="bytes">The bytes of the string.</param> /// <param name="unicode">Indicates whether one or two bytes are one character.</param> /// <param name="prefix">Indicates whether to use Unicode prefix.</param> /// <param name="hex">Indicates whether to create a hexadecimal string literal.</param> /// <param name="securityHandler">Encrypts the bytes if specified.</param> /// <returns>The PDF bytes.</returns> public static byte[] FormatStringLiteral(byte[] bytes, bool unicode, bool prefix, bool hex, PdfStandardSecurityHandler securityHandler) { if (bytes == null || bytes.Length == 0) { return hex ? new byte[] { (byte)'<', (byte)'>' } } : new byte[] { (byte)'(', (byte)')' }; Debug.Assert(!unicode || bytes.Length % 2 == 0, "Odd number of bytes in Unicode string."); byte[] originalBytes = null; bool encrypted = false; if (securityHandler != null && !hex) { originalBytes = bytes; bytes = (byte[])bytes.Clone(); bytes = securityHandler.EncryptBytes(bytes); encrypted = true; } int count = bytes.Length; StringBuilder pdf = new StringBuilder(); if (!unicode) { if (!hex) { pdf.Append("("); for (int idx = 0; idx < count; idx++) { char ch = (char)bytes[idx]; if (ch < 32) { switch (ch) { case '\n': pdf.Append("\\n"); break; case '\r': pdf.Append("\\r"); break; case '\t': pdf.Append("\\t"); break; case '\b': pdf.Append("\\b"); break; // Corrupts encrypted text. //case '\f': // pdf.Append("\\f"); // break; default: // Don't escape characters less than 32 if the string is encrypted, because it is // unreadable anyway. encrypted = true; if (!encrypted) { pdf.Append("\\0"); pdf.Append((char)(ch % 8 + '0')); pdf.Append((char)(ch / 8 + '0')); } else { pdf.Append(ch); } break; } } else { switch (ch) { case '(': pdf.Append("\\("); break; case ')': pdf.Append("\\)"); break; case '\\': pdf.Append("\\\\"); break; default: pdf.Append(ch); break; } } } pdf.Append(')'); } else { pdf.Append('<'); for (int idx = 0; idx < count; idx++) { pdf.AppendFormat("{0:X2}", bytes[idx]); } pdf.Append('>'); } } else { //Hex: if (hex) { if (securityHandler != null && prefix) { // TODO Reduce redundancy. // Encrypt data after padding BOM. var bytes2 = new byte[bytes.Length + 2]; // Add BOM. bytes2[0] = 0xfe; bytes2[1] = 0xff; // Copy bytes. Array.Copy(bytes, 0, bytes2, 2, bytes.Length); // Encyption. bytes2 = securityHandler.EncryptBytes(bytes2); encrypted = true; pdf.Append("<"); var count2 = bytes2.Length; for (int idx = 0; idx < count2; idx += 2) { pdf.AppendFormat("{0:X2}{1:X2}", bytes2[idx], bytes2[idx + 1]); if (idx != 0 && (idx % 48) == 0) { pdf.Append("\n"); } } pdf.Append(">"); } else { // No prefix or no encryption. pdf.Append(prefix ? "<FEFF" : "<"); for (int idx = 0; idx < count; idx += 2) { pdf.AppendFormat("{0:X2}{1:X2}", bytes[idx], bytes[idx + 1]); if (idx != 0 && (idx % 48) == 0) { pdf.Append("\n"); } } pdf.Append(">"); } } else { // TODO non hex literals... not sure how to treat linefeeds, '(', '\' etc. if (encrypted) { // Hack: Call self with hex := true. return(FormatStringLiteral(originalBytes, unicode, prefix, true, securityHandler)); } else { // Hack: Call self with hex := true. return(FormatStringLiteral(bytes, true, prefix, true, null)); } } } return(RawEncoding.GetBytes(pdf.ToString())); }
/// <summary> /// Converts the specified byte array into a byte array representing a string literal. /// </summary> /// <param name="bytes">The bytes of the string.</param> /// <param name="unicode">Indicates whether one or two bytes are one character.</param> /// <param name="prefix">Indicates whether to use Unicode prefix.</param> /// <param name="hex">Indicates whether to create a hexadecimal string literal.</param> /// <param name="securityHandler">Encrypts the bytes if specified.</param> /// <returns>The PDF bytes.</returns> public static byte[] FormatStringLiteral(byte[] bytes, bool unicode, bool prefix, bool hex, PdfStandardSecurityHandler securityHandler) { if (bytes == null || bytes.Length == 0) { return hex ? new byte[] { (byte)'<', (byte)'>' } } : new byte[] { (byte)'(', (byte)')' }; Debug.Assert(!unicode || bytes.Length % 2 == 0, "Odd number of bytes in Unicode string."); bool encrypted = false; if (securityHandler != null) { bytes = (byte[])bytes.Clone(); bytes = securityHandler.EncryptBytes(bytes); encrypted = true; } int count = bytes.Length; StringBuilder pdf = new StringBuilder(); if (!unicode) { if (!hex) { pdf.Append("("); for (int idx = 0; idx < count; idx++) { char ch = (char)bytes[idx]; if (ch < 32) { switch (ch) { case '\n': pdf.Append("\\n"); break; case '\r': pdf.Append("\\r"); break; case '\t': pdf.Append("\\t"); break; case '\b': pdf.Append("\\b"); break; // Corrupts encrypted text. //case '\f': // pdf.Append("\\f"); // break; default: // Don't escape characters less than 32 if the string is encrypted, because it is // unreadable anyway. encrypted = true; if (!encrypted) { pdf.Append("\\0"); pdf.Append((char)(ch % 8 + '0')); pdf.Append((char)(ch / 8 + '0')); } else { pdf.Append(ch); } break; } } else { switch (ch) { case '(': pdf.Append("\\("); break; case ')': pdf.Append("\\)"); break; case '\\': pdf.Append("\\\\"); break; default: pdf.Append(ch); break; } } } pdf.Append(')'); } else { pdf.Append('<'); for (int idx = 0; idx < count; idx++) { pdf.AppendFormat("{0:X2}", bytes[idx]); } pdf.Append('>'); } } else { Hex: if (hex) { pdf.Append(prefix ? "<FEFF" : "<"); for (int idx = 0; idx < count; idx += 2) { pdf.AppendFormat("{0:X2}{1:X2}", bytes[idx], bytes[idx + 1]); if (idx != 0 && (idx % 48) == 0) { pdf.Append("\n"); } } pdf.Append(">"); } else { // TODO non hex literals... not sure how to treat linefeeds, '(', '\' etc. hex = true; goto Hex; } } return(RawEncoding.GetBytes(pdf.ToString())); }