diff --git a/src/UglyToad.Pdf.Tests/ContentStream/PdfBooleanTests.cs b/src/UglyToad.Pdf.Tests/ContentStream/PdfBooleanTests.cs new file mode 100644 index 00000000..3e2fd2e4 --- /dev/null +++ b/src/UglyToad.Pdf.Tests/ContentStream/PdfBooleanTests.cs @@ -0,0 +1,129 @@ +namespace UglyToad.Pdf.Tests.ContentStream +{ + using System; + using System.IO; + using Pdf.ContentStream; + using Pdf.Util; + using Xunit; + + public class PdfBooleanTests + { + [Fact] + public void TrueIsTrue() + { + Assert.True(PdfBoolean.True.Value); + } + + [Fact] + public void FalseIsFalse() + { + Assert.False(PdfBoolean.False.Value); + } + + [Fact] + public void ImplicitTrueIsTrue() + { + Assert.True(PdfBoolean.True); + } + + [Fact] + public void ImplicitFalseIsFalse() + { + Assert.False(PdfBoolean.False); + } + + [Fact] + public void CastNullThrows() + { + PdfBoolean boolean = null; + + // ReSharper disable once ExpressionIsAlwaysNull + Action action = () => Test(boolean); + + Assert.Throws(action); + } + + [Fact] + public void StringRepresentationTrueCorrect() + { + Assert.Equal("true", PdfBoolean.True.ToString()); + } + + [Fact] + public void StringRepresentationFalseCorrect() + { + Assert.Equal("false", PdfBoolean.False.ToString()); + } + + [Fact] + public void OperatorEqualityWorksCorrectly() + { + // ReSharper disable once EqualExpressionComparison + Assert.True(PdfBoolean.True == PdfBoolean.True); + // ReSharper disable once EqualExpressionComparison + Assert.True(PdfBoolean.False == PdfBoolean.False); + + Assert.False(PdfBoolean.True == PdfBoolean.False); + Assert.False(PdfBoolean.False == PdfBoolean.True); + } + + [Fact] + public void EqualityWorksCorrectly() + { + var result = PdfBoolean.True.Equals(PdfBoolean.False); + + Assert.False(result); + + result = PdfBoolean.False.Equals(PdfBoolean.True); + + Assert.False(result); + + result = PdfBoolean.True.Equals(PdfBoolean.True); + + Assert.True(result); + + result = PdfBoolean.False.Equals(PdfBoolean.False); + + Assert.True(result); + } + + [Fact] + public void ObjectEqualityWorksCorrectly() + { + var result = PdfBoolean.True.Equals(null); + + Assert.False(result); + + // ReSharper disable once SuspiciousTypeConversion.Global + result = PdfBoolean.False.Equals("happy"); + + Assert.False(result); + + result = PdfBoolean.False.Equals((object) PdfBoolean.False); + + Assert.True(result); + } + + [Fact] + public void WritesToStreamCorrectly() + { + using (var memoryStream = new MemoryStream()) + using (var write = new BinaryWriter(memoryStream)) + { + PdfBoolean.True.WriteToPdfStream(write); + PdfBoolean.False.WriteToPdfStream(write); + + write.Flush(); + + var result = OtherEncodings.BytesAsLatin1String(memoryStream.ToArray()); + + Assert.Equal("truefalse", result); + } + } + + private static bool Test(bool input) + { + return input; + } + } +} diff --git a/src/UglyToad.Pdf.Tests/Filters/Ascii85FilterTests.cs b/src/UglyToad.Pdf.Tests/Filters/Ascii85FilterTests.cs index 1e367ed9..20959057 100644 --- a/src/UglyToad.Pdf.Tests/Filters/Ascii85FilterTests.cs +++ b/src/UglyToad.Pdf.Tests/Filters/Ascii85FilterTests.cs @@ -2,7 +2,7 @@ { using System; using System.Text; - using ContentStream; + using Pdf.ContentStream; using Pdf.Filters; using Xunit; diff --git a/src/UglyToad.Pdf.Tests/Filters/AsciiHexDecodeFilterTests.cs b/src/UglyToad.Pdf.Tests/Filters/AsciiHexDecodeFilterTests.cs index fcf1d6f1..d585d063 100644 --- a/src/UglyToad.Pdf.Tests/Filters/AsciiHexDecodeFilterTests.cs +++ b/src/UglyToad.Pdf.Tests/Filters/AsciiHexDecodeFilterTests.cs @@ -2,7 +2,7 @@ { using System; using System.Text; - using ContentStream; + using Pdf.ContentStream; using Pdf.Filters; using Xunit; diff --git a/src/UglyToad.Pdf.Tests/Filters/DecodeParameterResolverTests.cs b/src/UglyToad.Pdf.Tests/Filters/DecodeParameterResolverTests.cs index 8df89e41..f5ed244f 100644 --- a/src/UglyToad.Pdf.Tests/Filters/DecodeParameterResolverTests.cs +++ b/src/UglyToad.Pdf.Tests/Filters/DecodeParameterResolverTests.cs @@ -1,9 +1,8 @@ namespace UglyToad.Pdf.Tests.Filters { using System; - using ContentStream; using Parser.Parts; - using Pdf.Cos; + using Pdf.ContentStream; using Pdf.Filters; using Xunit; diff --git a/src/UglyToad.Pdf.Tests/Filters/RunLengthFilterTests.cs b/src/UglyToad.Pdf.Tests/Filters/RunLengthFilterTests.cs index 9129fd3b..9cf7a92c 100644 --- a/src/UglyToad.Pdf.Tests/Filters/RunLengthFilterTests.cs +++ b/src/UglyToad.Pdf.Tests/Filters/RunLengthFilterTests.cs @@ -1,6 +1,6 @@ namespace UglyToad.Pdf.Tests.Filters { - using ContentStream; + using Pdf.ContentStream; using Pdf.Filters; using Xunit; diff --git a/src/UglyToad.Pdf.Tests/Graphics/TestOperationContext.cs b/src/UglyToad.Pdf.Tests/Graphics/TestOperationContext.cs index 6990b39b..c141c542 100644 --- a/src/UglyToad.Pdf.Tests/Graphics/TestOperationContext.cs +++ b/src/UglyToad.Pdf.Tests/Graphics/TestOperationContext.cs @@ -4,6 +4,7 @@ using Content; using ContentStream; using IO; + using Pdf.ContentStream; using Pdf.Cos; using Pdf.Fonts; using Pdf.Graphics; diff --git a/src/UglyToad.Pdf.Tests/Integration/PdfParserTests.cs b/src/UglyToad.Pdf.Tests/Integration/PdfParserTests.cs index 32309e5e..24043fae 100644 --- a/src/UglyToad.Pdf.Tests/Integration/PdfParserTests.cs +++ b/src/UglyToad.Pdf.Tests/Integration/PdfParserTests.cs @@ -6,7 +6,7 @@ using System.IO.Compression; using System.Linq; using System.Text; - using ContentStream; + using Pdf.ContentStream; using Pdf.Cos; using Pdf.Filters; using Xunit; diff --git a/src/UglyToad.Pdf.Tests/TestDictionaryParser.cs b/src/UglyToad.Pdf.Tests/TestDictionaryParser.cs index 8baab883..d522f520 100644 --- a/src/UglyToad.Pdf.Tests/TestDictionaryParser.cs +++ b/src/UglyToad.Pdf.Tests/TestDictionaryParser.cs @@ -1,7 +1,7 @@ namespace UglyToad.Pdf.Tests { - using ContentStream; using IO; + using Pdf.ContentStream; using Pdf.Cos; using Pdf.Parser.Parts; diff --git a/src/UglyToad.Pdf.Tests/Tokenization/DictionaryTokenizerTests.cs b/src/UglyToad.Pdf.Tests/Tokenization/DictionaryTokenizerTests.cs index def8876b..9b2644bd 100644 --- a/src/UglyToad.Pdf.Tests/Tokenization/DictionaryTokenizerTests.cs +++ b/src/UglyToad.Pdf.Tests/Tokenization/DictionaryTokenizerTests.cs @@ -3,7 +3,7 @@ namespace UglyToad.Pdf.Tests.Tokenization { using System; using System.Collections.Generic; - using ContentStream; + using Pdf.ContentStream; using Pdf.Cos; using Pdf.Tokenization; using Pdf.Tokenization.Tokens; diff --git a/src/UglyToad.Pdf/Content/PageTreeNode.cs b/src/UglyToad.Pdf/Content/PageTreeNode.cs deleted file mode 100644 index 96210c22..00000000 --- a/src/UglyToad.Pdf/Content/PageTreeNode.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace UglyToad.Pdf.Content -{ - using System; - using Cos; - - public class PageTreeNode - { - private readonly CosDictionary dictionary; - - public int Count { get; set; } - - public PageTreeNode Parent { get; } - - internal PageTreeNode(CosDictionary pageTreeNode, PageTreeNode parent) - { - dictionary = pageTreeNode ?? throw new ArgumentNullException(nameof(pageTreeNode)); - - Parent = parent; - - } - } -} diff --git a/src/UglyToad.Pdf/ContentStream/PdfBoolean.cs b/src/UglyToad.Pdf/ContentStream/PdfBoolean.cs new file mode 100644 index 00000000..945ad3c8 --- /dev/null +++ b/src/UglyToad.Pdf/ContentStream/PdfBoolean.cs @@ -0,0 +1,117 @@ +namespace UglyToad.Pdf.ContentStream +{ + using System; + using System.Collections.Generic; + using System.IO; + using Core; + using Cos; + + internal class PdfBoolean : CosBase, ICosStreamWriter, IEquatable + { + /// + /// The bytes representing a true value in the PDF content. + /// + /// Equivalent to the text "true". + private static readonly byte[] TrueBytes = {116, 114, 117, 101}; + + /// + /// The bytes representing a false value in the PDF content. + /// + /// Equivalent to the text "false". + private static readonly byte[] FalseBytes = {102, 97, 108, 115, 101}; + + /// + /// The PDF boolean representing . + /// + public static PdfBoolean True { get; } = new PdfBoolean(true); + + /// + /// The PDF boolean representing . + /// + public static PdfBoolean False { get; } = new PdfBoolean(false); + + /// + /// The boolean value. + /// + public bool Value { get; } + + private PdfBoolean(bool value) + { + Value = value; + } + + public override object Accept(ICosVisitor visitor) + { + return visitor.VisitFromBoolean(this); + } + + /// + /// Supports casting from to . + /// + public static explicit operator PdfBoolean(bool value) + { + return value ? True : False; + } + + /// + /// Supports treatment of as a . + /// + public static implicit operator bool(PdfBoolean value) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + return value.Value; + } + + public static bool operator ==(PdfBoolean boolean1, PdfBoolean boolean2) + { + return EqualityComparer.Default.Equals(boolean1, boolean2); + } + + public static bool operator !=(PdfBoolean boolean1, PdfBoolean boolean2) + { + return !(boolean1 == boolean2); + } + + public override string ToString() + { + return Value ? "true" : "false"; + } + + public void WriteToPdfStream(BinaryWriter output) + { + if (output == null) + { + throw new ArgumentNullException(nameof(output)); + } + + if (Value) + { + output.Write(TrueBytes); + } + else + { + output.Write(FalseBytes); + } + } + + public override bool Equals(object obj) + { + return Equals(obj as PdfBoolean); + } + + public bool Equals(PdfBoolean other) + { + return other != null && + Value == other.Value; + } + + public override int GetHashCode() + { + return -1937169414 + Value.GetHashCode(); + } + } +} diff --git a/src/UglyToad.Pdf/Core/ICosStreamWriter.cs b/src/UglyToad.Pdf/Core/ICosStreamWriter.cs index 0e045519..259e3b58 100644 --- a/src/UglyToad.Pdf/Core/ICosStreamWriter.cs +++ b/src/UglyToad.Pdf/Core/ICosStreamWriter.cs @@ -4,6 +4,6 @@ public interface ICosStreamWriter { - void WriteToPdfStream(StreamWriter output); + void WriteToPdfStream(BinaryWriter output); } } diff --git a/src/UglyToad.Pdf/Cos/CosBoolean.cs b/src/UglyToad.Pdf/Cos/CosBoolean.cs deleted file mode 100644 index 82aa9c04..00000000 --- a/src/UglyToad.Pdf/Cos/CosBoolean.cs +++ /dev/null @@ -1,73 +0,0 @@ -namespace UglyToad.Pdf.Cos -{ - using System.IO; - using Core; - - internal class CosBoolean : CosBase, ICosStreamWriter - { - /** - * The true boolean token. - */ - public static readonly byte[] TrueBytes = { 116, 114, 117, 101 }; //"true".getBytes( "ISO-8859-1" ); - /** - * The false boolean token. - */ - public static readonly byte[] FalseBytes = { 102, 97, 108, 115, 101 }; //"false".getBytes( "ISO-8859-1" ); - - /** - * The PDF true value. - */ - public static readonly CosBoolean True = new CosBoolean(true); - - /** - * The PDF false value. - */ - public static readonly CosBoolean False = new CosBoolean(false); - - public bool Value { get; } - - private CosBoolean(bool value) - { - Value = value; - } - - /** - * This will get the boolean value. - * - * @param value Parameter telling which boolean value to get. - * - * @return The single boolean instance that matches the parameter. - */ - public static explicit operator CosBoolean(bool value) - { - return value ? True : False; - } - - /** - * Return a string representation of this object. - * - * @return The string value of this object. - */ - public override string ToString() - { - return Value.ToString(); - } - - /** - * This will write this object out to a PDF stream. - * - * @param output The stream to write this object out to. - * - * @throws IOException If an error occurs while writing out this object. - */ - public void WriteToPdfStream(StreamWriter output) - { - output.Write(Value ? TrueBytes : FalseBytes); - } - - public override object Accept(ICosVisitor visitor) - { - return visitor.VisitFromBoolean(this); - } - } -} diff --git a/src/UglyToad.Pdf/Cos/CosDictionary.cs b/src/UglyToad.Pdf/Cos/CosDictionary.cs index 9e49b871..acc9d53e 100644 --- a/src/UglyToad.Pdf/Cos/CosDictionary.cs +++ b/src/UglyToad.Pdf/Cos/CosDictionary.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Text; using System.Linq; + using ContentStream; using Util; internal class CosDictionary : CosBase, ICosUpdateInfo @@ -238,7 +239,7 @@ */ public void setbool(String key, bool value) { - setItem(CosName.Create(key), (CosBoolean)value); + setItem(CosName.Create(key), (PdfBoolean)value); } /** @@ -249,7 +250,7 @@ */ public void setbool(CosName key, bool value) { - setItem(key, (CosBoolean)value); + setItem(key, (PdfBoolean)value); } /** @@ -919,9 +920,9 @@ { bool retval = defaultValue; CosBase boolValue = getDictionaryObject(firstKey, secondKey); - if (boolValue is CosBoolean) + if (boolValue is PdfBoolean) { - retval = ((CosBoolean)boolValue).Value; + retval = ((PdfBoolean)boolValue).Value; } return retval; diff --git a/src/UglyToad.Pdf/Cos/CosFloat.cs b/src/UglyToad.Pdf/Cos/CosFloat.cs index 1ff7547c..48824da3 100644 --- a/src/UglyToad.Pdf/Cos/CosFloat.cs +++ b/src/UglyToad.Pdf/Cos/CosFloat.cs @@ -139,7 +139,7 @@ namespace UglyToad.Pdf.Cos return "COSFloat{" + valueAsString + "}"; } - public void WriteToPdfStream(StreamWriter output) + public void WriteToPdfStream(BinaryWriter output) { var encoding = Encoding.GetEncoding("ISO-8859-1"); output.Write(encoding.GetBytes(valueAsString)); diff --git a/src/UglyToad.Pdf/Cos/CosInt.cs b/src/UglyToad.Pdf/Cos/CosInt.cs index a29b4b2c..7cab3c9a 100644 --- a/src/UglyToad.Pdf/Cos/CosInt.cs +++ b/src/UglyToad.Pdf/Cos/CosInt.cs @@ -103,7 +103,7 @@ namespace UglyToad.Pdf.Cos return "COSInt{" + value + "}"; } - public void WriteToPdfStream(StreamWriter output) + public void WriteToPdfStream(BinaryWriter output) { var encoding = Encoding.GetEncoding("ISO-8859-1"); diff --git a/src/UglyToad.Pdf/Cos/CosName.cs b/src/UglyToad.Pdf/Cos/CosName.cs index d36a3e3e..6588bb8c 100644 --- a/src/UglyToad.Pdf/Cos/CosName.cs +++ b/src/UglyToad.Pdf/Cos/CosName.cs @@ -604,7 +604,7 @@ namespace UglyToad.Pdf.Cos return $"/{Name}"; } - public void WriteToPdfStream(StreamWriter output) + public void WriteToPdfStream(BinaryWriter output) { output.Write('/'); byte[] bytes = Encoding.ASCII.GetBytes(Name); diff --git a/src/UglyToad.Pdf/Cos/CosNull.cs b/src/UglyToad.Pdf/Cos/CosNull.cs index 3b05cb5c..1b523258 100644 --- a/src/UglyToad.Pdf/Cos/CosNull.cs +++ b/src/UglyToad.Pdf/Cos/CosNull.cs @@ -29,14 +29,14 @@ namespace UglyToad.Pdf.Cos return visitor.VisitFromNull(this); } - public void WriteToPdfStream(StreamWriter output) + public void WriteToPdfStream(BinaryWriter output) { output.Write(NullBytes); } public override string ToString() { - return "COSNull{}"; + return "COSNull"; } } } diff --git a/src/UglyToad.Pdf/Cos/ICosVisitor.cs b/src/UglyToad.Pdf/Cos/ICosVisitor.cs index e55ad2e5..9e7a9ca6 100644 --- a/src/UglyToad.Pdf/Cos/ICosVisitor.cs +++ b/src/UglyToad.Pdf/Cos/ICosVisitor.cs @@ -1,5 +1,7 @@ namespace UglyToad.Pdf.Cos { + using ContentStream; + /** * An interface for visiting a PDF document at the type (COS) level. * @@ -23,7 +25,7 @@ * @return any Object depending on the visitor implementation, or null * @throws IOException If there is an error while visiting this object. */ - object VisitFromBoolean(CosBoolean obj); + object VisitFromBoolean(PdfBoolean obj); /** * Notification of visit to dictionary object. diff --git a/src/UglyToad.Pdf/Parser/Parts/CosBaseParser.cs b/src/UglyToad.Pdf/Parser/Parts/CosBaseParser.cs index 8b44b465..fe6d531b 100644 --- a/src/UglyToad.Pdf/Parser/Parts/CosBaseParser.cs +++ b/src/UglyToad.Pdf/Parser/Parts/CosBaseParser.cs @@ -2,6 +2,7 @@ { using System.IO; using System.Text; + using ContentStream; using Cos; using IO; using Util; @@ -85,7 +86,7 @@ string truestring = OtherEncodings.BytesAsLatin1String(reader.ReadFully(4)); if (truestring.Equals("true")) { - retval = CosBoolean.True; + retval = PdfBoolean.True; } else { @@ -99,7 +100,7 @@ string falsestring = OtherEncodings.BytesAsLatin1String(reader.ReadFully(5)); if (falsestring.Equals("false")) { - retval = CosBoolean.False; + retval = PdfBoolean.False; } else { diff --git a/src/UglyToad.Pdf/Util/Hex.cs b/src/UglyToad.Pdf/Util/Hex.cs index 3e244adb..0217e817 100644 --- a/src/UglyToad.Pdf/Util/Hex.cs +++ b/src/UglyToad.Pdf/Util/Hex.cs @@ -1,10 +1,7 @@ -using System; -using System.Text; -using System.IO; - -namespace UglyToad.Pdf.Util +namespace UglyToad.Pdf.Util { - + using System.Text; + using System.IO; /** * Utility functions for hex encoding. * @@ -24,15 +21,6 @@ namespace UglyToad.Pdf.Util private Hex() { } - /** - * Returns a hex string of the given byte. - */ - public static string GetString(byte b) - { - char[] chars = { HexChars[GetHighNibble(b)], HexChars[GetLowNibble(b)] }; - return new String(chars); - } - /** * Returns a hex string of the given byte array. */ @@ -48,79 +36,13 @@ namespace UglyToad.Pdf.Util return stringBuilder.ToString(); } - /** - * Returns the bytes corresponding to the ASCII hex encoding of the given byte. - */ - public static byte[] GetBytes(byte b) - { - return new[] { HexBytes[GetHighNibble(b)], HexBytes[GetLowNibble(b)] }; - } - - /** - * Returns the bytes corresponding to the ASCII hex encoding of the given bytes. - */ - public static byte[] GetBytes(byte[] bytes) - { - byte[] asciiBytes = new byte[bytes.Length * 2]; - for (int i = 0; i < bytes.Length; i++) - { - asciiBytes[i * 2] = HexBytes[GetHighNibble(bytes[i])]; - asciiBytes[i * 2 + 1] = HexBytes[GetLowNibble(bytes[i])]; - } - return asciiBytes; - } - - /** - * Returns the characters corresponding to the ASCII hex encoding of the given short. - */ - public static char[] GetChars(short num) - { - char[] hex = new char[4]; - hex[0] = HexChars[(num >> 12) & 0x0F]; - hex[1] = HexChars[(num >> 8) & 0x0F]; - hex[2] = HexChars[(num >> 4) & 0x0F]; - hex[3] = HexChars[num & 0x0F]; - return hex; - } - - /** - * Takes the characters in the given string, convert it to bytes in UTF16-BE format - * and build a char array that corresponds to the ASCII hex encoding of the resulting - * bytes. - * - * Example: - *
-         *   getCharsUTF16BE("ab") == new char[]{'0','0','6','1','0','0','6','2'}
-         * 
- * - * @param text The string to convert - * @return The string converted to hex - */ - public static char[] GetCharsUtf16Be(String text) - { - // Note that the internal representation of string in Java is already UTF-16. Therefore - // we do not need to use an encoder to convert the string to its byte representation. - char[] hex = new char[text.Length * 4]; - - for (int stringIdx = 0, charIdx = 0; stringIdx < text.Length; stringIdx++) - { - char c = text[stringIdx]; - hex[charIdx++] = HexChars[(c >> 12) & 0x0F]; - hex[charIdx++] = HexChars[(c >> 8) & 0x0F]; - hex[charIdx++] = HexChars[(c >> 4) & 0x0F]; - hex[charIdx++] = HexChars[c & 0x0F]; - } - - return hex; - } - /** * Writes the given byte as hex value to the given output stream. * @param b the byte to be written * @param output the output stream to be written to * @throws IOException exception if anything went wrong */ - public static void WriteHexByte(byte b, StreamWriter output) + public static void WriteHexByte(byte b, BinaryWriter output) { output.Write(HexBytes[GetHighNibble(b)]); output.Write(HexBytes[GetLowNibble(b)]); @@ -132,7 +54,7 @@ namespace UglyToad.Pdf.Util * @param output the output stream to be written to * @throws IOException exception if anything went wrong */ - public static void WriteHexBytes(byte[] bytes, StreamWriter output) + public static void WriteHexBytes(byte[] bytes, BinaryWriter output) { foreach (var b in bytes) {