Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.IO;
- using System.Collections;
- namespace ConsoleTest
- {
- class COSParse
- {
- const string whiteSpaces = " \r\n\t";
- const string blockTerminators = whiteSpaces + "/[]<>()";
- const string numbers = "0123456789";
- public const string cosNumberFilter = "0123456789.";
- MemoryStream stream;
- BinaryReader reader;
- List<COSObj> objects = new List<COSObj>();
- public COSParse(string filePath)
- {
- this.stream = new MemoryStream();
- FileStream file = new FileStream(filePath, FileMode.Open);
- file.CopyTo(this.stream);
- file.Close();
- this.reader = new BinaryReader(this.stream, Encoding.GetEncoding(1252));
- this.reader.BaseStream.Seek(0, SeekOrigin.Begin);
- this.ParseStream();
- }
- #region Document Level
- public void ParseStream()
- {
- while (this.reader.BaseStream.Position < this.reader.BaseStream.Length)
- {
- if ((char)this.reader.PeekChar() == '%') SkipComment(this.reader);
- else if (numbers.Contains((char)reader.PeekChar())) this.objects.Add(this.ParseNextObject());
- else if (this.ContinueWith(this.reader, "startxref")) this.ParseStartXref();
- else
- {
- throw new Exception($"Unknown Char: {reader.PeekChar()}: {(char)reader.PeekChar()}");
- }
- this.SkipWhiteSpaces(this.reader);
- }
- }
- public COSObj ParseNextObject()
- {
- string objectID = ReadBlock(reader);
- string objectRevision = ReadBlock(reader);
- string objSuffix = ReadBlock(reader);
- this.SkipToNextBlock(reader);
- COSType data = ParseNextData(reader);
- this.SkipToNextBlock(reader);
- if (this.ContinueWith(reader, "endobj"))
- {
- this.reader.ReadChar(); //e
- this.reader.ReadChar(); //n
- this.reader.ReadChar(); //d
- this.reader.ReadChar(); //o
- this.reader.ReadChar(); //b
- this.reader.ReadChar(); //j
- return new COSObject(int.Parse(objectID), int.Parse(objectRevision), data);
- }
- else if (this.ContinueWith(reader, "stream"))
- {
- List<byte> streamData = new List<byte>();
- while (!this.ContinueWith(reader, "endstream"))
- {
- streamData.Add(reader.ReadByte());
- }
- this.reader.ReadChar(); //e
- this.reader.ReadChar(); //n
- this.reader.ReadChar(); //d
- this.reader.ReadChar(); //s
- this.reader.ReadChar(); //t
- this.reader.ReadChar(); //r
- this.reader.ReadChar(); //e
- this.reader.ReadChar(); //a
- this.reader.ReadChar(); //m
- this.SkipWhiteSpaces(reader);
- this.reader.ReadChar(); //e
- this.reader.ReadChar(); //n
- this.reader.ReadChar(); //d
- this.reader.ReadChar(); //o
- this.reader.ReadChar(); //b
- this.reader.ReadChar(); //j
- return new COSStreamObject(int.Parse(objectID), int.Parse(objectRevision), data as COSDictionary, streamData.ToArray());
- }
- else throw new Exception("Invalid object");
- }
- public void ParseStartXref()
- {
- while (!this.ContinueWith(this.reader, "%%EOF")) this.reader.ReadChar();
- this.reader.ReadChar(); //%
- this.reader.ReadChar(); //%
- this.reader.ReadChar(); //E
- this.reader.ReadChar(); //O
- this.reader.ReadChar(); //F
- }
- #endregion
- #region Object Level
- public COSType ParseNextData(BinaryReader reader)
- {
- if (this.ContinueWith(reader, "<<")) return ParseDictionary(reader);
- else if (reader.PeekChar() == '<' || reader.PeekChar() == '(') return ParseString(reader);
- else if (reader.PeekChar() == '/') return ParseName(reader);
- else if (this.reader.PeekChar() == '[') return ParseArray(reader);
- else if (this.ContinueWith(reader, "true") || this.ContinueWith(reader, "false")) return ParseBool(reader);
- else if (cosNumberFilter.Contains((char)reader.PeekChar())) //Number [num] / Indirect reference [int int, 'R']
- {
- int num1v = 0;
- string num1 = ReadBlock(reader);
- long curPos = reader.BaseStream.Position;
- this.SkipToNextBlock(reader);
- if (int.TryParse(num1, out num1v)) //Integer / Indirect Ref
- {
- int num2v = 0;
- string num2 = ReadBlock(reader);
- this.SkipToNextBlock(reader);
- if (int.TryParse(num2, out num2v)) //2x Multiple integer / Indirect Ref
- {
- string letter = ReadBlock(reader);
- if (letter == "R") return new COSReference(num1v, num2v); //Indirect Ref
- }
- }
- reader.BaseStream.Seek(curPos, SeekOrigin.Begin);
- return new COSNumber(num1);
- }
- else return null;
- }
- public COSDictionary ParseDictionary(BinaryReader reader)
- {
- COSDictionary ret = new COSDictionary();
- reader.ReadChar(); //<
- reader.ReadChar(); //<
- SkipToNextBlock(reader);
- while (!this.ContinueWith(reader, ">>"))
- {
- //Parse Dictionary Name
- COSName key = ParseName(reader);
- this.SkipToNextBlock(reader);
- COSType value = ParseNextData(reader);
- ret.Add(key, value);
- }
- this.SkipToNextBlock(reader);
- reader.ReadChar(); //>
- reader.ReadChar(); //>
- return ret;
- }
- private COSName ParseName(BinaryReader reader)
- {
- return new COSName(ReadBlock(reader));
- }
- private COSArray ParseArray(BinaryReader reader)
- {
- reader.ReadChar(); // '['
- SkipToNextBlock(reader);
- if (reader.PeekChar() == ']') return new COSArray(new COSType[0]); //Empty array
- else
- {
- List<COSType> entries = new List<COSType>();
- while (reader.PeekChar() != ']')
- {
- entries.Add(this.ParseNextData(reader));
- this.SkipToNextBlock(reader);
- }
- reader.ReadChar(); // ']'
- return new COSArray(entries.ToArray());
- }
- }
- private COSString ParseString(BinaryReader reader)
- {
- string block = this.ReadBlock(reader);
- block += (char)reader.ReadByte();
- return new COSString(block);
- }
- private COSBool ParseBool(BinaryReader reader)
- {
- if (this.ContinueWith(reader, "true"))
- {
- reader.ReadChar(); //t
- reader.ReadChar(); //r
- reader.ReadChar(); //u
- reader.ReadChar(); //e
- return new COSBool(true);
- }
- else if (this.ContinueWith(reader, "false"))
- {
- reader.ReadChar(); //f
- reader.ReadChar(); //a
- reader.ReadChar(); //l
- reader.ReadChar(); //s
- reader.ReadChar(); //e
- return new COSBool(false);
- }
- else throw new Exception("Invalid COS bool value");
- }
- #endregion
- #region Helpers
- private void SkipComment(BinaryReader reader)
- {
- if (reader.PeekChar() == '%')
- {
- reader.ReadChar();
- SkipToNextLine(reader);
- }
- }
- private void SkipToNextLine(BinaryReader reader)
- {
- while (reader.BaseStream.Position < reader.BaseStream.Length && reader.PeekChar() != '\r' && reader.PeekChar() != '\n') reader.ReadChar();
- if (reader.PeekChar() == '\r' || reader.PeekChar() == '\n')
- {
- while (reader.BaseStream.Position < reader.BaseStream.Length && (reader.PeekChar() == '\r' || reader.PeekChar() == '\n')) reader.ReadChar();
- }
- }
- private void SkipWhiteSpaces(BinaryReader reader)
- {
- while (reader.BaseStream.Position < reader.BaseStream.Length && whiteSpaces.Contains((char)reader.PeekChar())) reader.ReadChar();
- if (reader.PeekChar() == '\r' || reader.PeekChar() == '\n')
- {
- while (reader.BaseStream.Position < reader.BaseStream.Length && (reader.PeekChar() == '\r' || reader.PeekChar() == '\n')) reader.ReadChar();
- }
- }
- private void SkipToNextBlock(BinaryReader reader)
- {
- SkipWhiteSpaces(reader);
- while (reader.PeekChar() == '%')
- {
- SkipToNextLine(reader);
- SkipWhiteSpaces(reader);
- }
- }
- private string ReadBlock(BinaryReader reader)
- {
- this.SkipWhiteSpaces(reader);
- string ret = ((char)reader.ReadByte()).ToString();
- while (!blockTerminators.Contains((char)reader.PeekChar())) ret += (char)reader.ReadByte();
- return ret;
- }
- private bool ContinueWith(BinaryReader reader, string value)
- {
- long startPos = reader.BaseStream.Position;
- if (value.Length > 0 && (char)reader.PeekChar() == value[0] && reader.BaseStream.Length - reader.BaseStream.Position >= value.Length)
- {
- bool ret = true;
- for (int i = 0; i < value.Length && ret; i++)
- {
- ret &= value[i] == (char)reader.ReadChar();
- }
- reader.BaseStream.Seek(startPos, SeekOrigin.Begin);
- return ret;
- }
- else return false;
- }
- #endregion
- public string ToString(int ident)
- {
- string prefix = new string('\t', ident);
- string ret = $"{prefix}DOC{Environment.NewLine}";
- ret += $"{prefix}{{{Environment.NewLine}";
- foreach (COSObj obj in this.objects) ret += obj.ToString(ident + 1) + Environment.NewLine;
- ret += $"{prefix}}}{Environment.NewLine}";
- return ret;
- }
- }
- interface COSObj { string ToString(int ident); }
- class COSObject : COSObj
- {
- int ID;
- int revision;
- COSType data;
- public COSObject(int ID, int revision, COSType data)
- {
- this.ID = ID;
- this.revision = revision;
- this.data = data;
- }
- public string ToString(int ident)
- {
- string prefix = new string('\t', ident);
- string ret = $"{prefix}OBJ ID[{ID}] REVISION[{revision}]{Environment.NewLine}";
- ret += $"{prefix}{{{Environment.NewLine}";
- ret += data.ToString(ident + 1) + Environment.NewLine;
- ret += $"{prefix}}}{Environment.NewLine}";
- return ret;
- }
- }
- class COSStreamObject : MemoryStream, COSObj
- {
- int ID;
- int revision;
- COSDictionary attributes;
- public COSStreamObject(int ID, int revision, COSDictionary attributes, byte[] data) : base(data)
- {
- this.ID = ID;
- this.revision = revision;
- this.attributes = attributes;
- }
- public string ToString(int ident)
- {
- string prefix = new string('\t', ident);
- string prefix2 = new string('\t', ident + 1);
- string ret = $"{prefix}OBJ ID[{ID}] REVISION[{revision}]{Environment.NewLine}";
- ret += $"{prefix}{{{Environment.NewLine}";
- ret += $"{prefix2}ATTRIBUTES{Environment.NewLine}";
- ret += $"{prefix2}{{{Environment.NewLine}";
- ret += prefix2 + attributes.ToString(ident + 1, true) + Environment.NewLine;
- ret += $"{prefix2}}}{Environment.NewLine}";
- this.Seek(0, SeekOrigin.Begin);
- ret += $"{prefix2}BODY [";
- while (this.Position < this.Length) ret += " 0x" + this.ReadByte().ToString("X2");
- ret += $" ]{Environment.NewLine}";
- ret += $"{prefix}}}{Environment.NewLine}";
- return ret;
- }
- }
- interface COSType { string ToString(int ident); }
- class COSName : COSType
- {
- public string name;
- public COSName(string name)
- {
- if (name[0] != '/' || name.Length < 2) throw new Exception("Invalid COS name, COS names must start with '/' and must be at least 2 char long");
- this.name = name.Substring(1);
- }
- public override string ToString()
- {
- return $"/{name}";
- }
- public override bool Equals(object obj)
- {
- return obj is COSName && (obj as COSName).name.Equals(this.name);
- }
- public override int GetHashCode()
- {
- return this.name.GetHashCode();
- }
- public string ToString(int ident)
- {
- string prefix = new string('\t', ident);
- return $"{prefix}{this.ToString()}";
- }
- }
- class COSDictionary : COSType, IDictionary<COSName, COSType>
- {
- Dictionary<COSName, COSType> dict;
- public COSDictionary()
- {
- this.dict = new Dictionary<COSName, COSType>();
- }
- public COSType this[COSName key]
- {
- get { return dict[key]; }
- set { dict[key] = value; }
- }
- public int Count
- {
- get { return dict.Count; }
- }
- public bool IsReadOnly
- {
- get { return false; }
- }
- public ICollection<COSName> Keys
- {
- get { return dict.Keys; }
- }
- public ICollection<COSType> Values
- {
- get { return dict.Values; }
- }
- public void Add(KeyValuePair<COSName, COSType> item)
- {
- dict.Add(item.Key, item.Value);
- }
- public void Add(COSName key, COSType value)
- {
- dict.Add(key, value);
- }
- public void Clear()
- {
- dict.Clear();
- }
- public bool Contains(KeyValuePair<COSName, COSType> item)
- {
- return dict.Contains(item);
- }
- public bool ContainsKey(COSName key)
- {
- return dict.ContainsKey(key);
- }
- public void CopyTo(KeyValuePair<COSName, COSType>[] array, int arrayIndex)
- {
- throw new NotImplementedException();
- }
- public IEnumerator<KeyValuePair<COSName, COSType>> GetEnumerator()
- {
- return dict.GetEnumerator();
- }
- public bool Remove(KeyValuePair<COSName, COSType> item)
- {
- return dict.Remove(item.Key);
- }
- public bool Remove(COSName key)
- {
- return dict.Remove(key);
- }
- public string ToString(int ident)
- {
- return this.ToString(ident, false);
- }
- public string ToString(int ident, bool multiLine)
- {
- string prefix = new string('\t', ident);
- string ret = prefix + "{";
- foreach (KeyValuePair<COSName, COSType> item in this) ret += $" {item.Key}: {item.Value}";
- return ret + " }";
- }
- public bool TryGetValue(COSName key, out COSType value)
- {
- return dict.TryGetValue(key, out value);
- }
- IEnumerator IEnumerable.GetEnumerator()
- {
- return dict.GetEnumerator();
- }
- }
- class COSNumber : COSType
- {
- string value;
- public COSNumber(string number)
- {
- for (int i = 0; i < number.Length; i++) if (!COSParse.cosNumberFilter.Contains(number[i])) throw new Exception($"Invalid COS number: {number}");
- this.value = number;
- }
- public override string ToString()
- {
- return value;
- }
- public override bool Equals(object obj)
- {
- return obj is COSNumber && (obj as COSNumber).value == this.value;
- }
- public override int GetHashCode()
- {
- return this.value.GetHashCode();
- }
- public string ToString(int ident)
- {
- string prefix = new string('\t', ident);
- return $"{prefix}{this.value}";
- }
- }
- class COSArray : COSType
- {
- COSType[] values;
- public COSArray(COSType[] values)
- {
- if (values.Length > 0)
- {
- Type t = values[0].GetType();
- for (int i = 1; i < values.Length; i++)
- {
- if (values[i].GetType() != t) throw new Exception("COS array must consist of elements from the same type");
- }
- }
- this.values = values;
- }
- public override bool Equals(object obj)
- {
- return obj is COSArray && (obj as COSArray).values.Equals(this.values);
- }
- public override int GetHashCode()
- {
- return this.values.GetHashCode();
- }
- public override string ToString()
- {
- string ret = "[";
- foreach (COSType item in this.values) ret += " " + item.ToString(0);
- ret += " ]";
- return ret;
- }
- public string ToString(int ident)
- {
- string prefix = new string('\t', ident);
- return $"{prefix}{this.ToString()}";
- }
- }
- class COSString : COSType
- {
- public string value;
- public bool isHex;
- public COSString(string value)
- {
- if (value[0] == '(' && value[value.Length-1] == ')')
- {
- this.value = value.Substring(1, value.Length - 2);
- this.isHex = false;
- }
- else if (value[0] == '<' && value[value.Length - 1] == '>')
- {
- value = value.Substring(1, value.Length - 2);
- this.value = "";
- for (int i = 0; i < value.Length; i += 2)
- {
- this.value += (char)Convert.ToInt32(value.Substring(i, 2), 16);
- this.isHex = true;
- }
- }
- }
- public string ToString(int ident)
- {
- string prefix = new string('\t', ident);
- if (this.isHex)
- {
- string ret = $"{prefix}<";
- for (int i = 0; i < this.value.Length; i++) ret += " 0x" + ((int)this.value[i]).ToString("X2");
- ret += " >";
- return ret;
- }
- else return $"{prefix}({value})";
- }
- }
- class COSReference : COSType
- {
- public int objectID;
- public int objectRevision;
- public COSReference(int objectID, int objectRevision)
- {
- this.objectID = objectID;
- this.objectRevision = objectRevision;
- }
- public override string ToString()
- {
- return $"{objectID} {objectRevision} R";
- }
- public string ToString(int ident)
- {
- string prefix = new string('\t', ident);
- return prefix + this.ToString();
- }
- }
- class COSBool : COSType
- {
- bool value;
- public COSBool(bool value)
- {
- this.value = value;
- }
- public override string ToString()
- {
- return this.value.ToString();
- }
- public string ToString(int ident)
- {
- string prefix = new string('\t', ident);
- return prefix + this.value.ToString();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement