internal static CoreTokenScanner Scanner(string s) { var result = new CoreTokenScanner(new ByteArrayInputBytes(OtherEncodings.StringAsLatin1Bytes(s))); return(result); }
private static StreamInputBytes StringToStream(string str) => new StreamInputBytes(new MemoryStream(OtherEncodings.StringAsLatin1Bytes(str)));
private static void WriteInt(int value, Stream outputStream) { var bytes = OtherEncodings.StringAsLatin1Bytes(value.ToString("G")); outputStream.Write(bytes, 0, bytes.Length); }
public void ArrayAndStreamBehaveTheSame() { var bytes = OtherEncodings.StringAsLatin1Bytes(TestData); var array = new ByteArrayInputBytes(bytes); using (var memoryStream = new MemoryStream(bytes)) { var stream = new StreamInputBytes(memoryStream); Assert.Equal(bytes.Length, array.Length); Assert.Equal(bytes.Length, stream.Length); Assert.Equal(0, array.CurrentOffset); Assert.Equal(0, stream.CurrentOffset); array.Seek(5); stream.Seek(5); Assert.Equal(array.CurrentOffset, stream.CurrentOffset); Assert.Equal((byte)'5', array.CurrentByte); Assert.Equal(array.CurrentByte, stream.CurrentByte); Assert.Equal(array.Peek(), stream.Peek()); array.Seek(0); stream.Seek(0); Assert.Equal(0, array.CurrentByte); Assert.Equal(array.CurrentByte, stream.CurrentByte); array.Seek(7); stream.Seek(7); var arrayString = string.Empty; var streamString = string.Empty; while (array.MoveNext()) { arrayString += (char)array.CurrentByte; } while (stream.MoveNext()) { streamString += (char)stream.CurrentByte; } Assert.Equal("89", streamString); Assert.Equal(arrayString, streamString); Assert.True(stream.IsAtEnd()); Assert.True(array.IsAtEnd()); stream.Seek(0); array.Seek(0); Assert.False(stream.IsAtEnd()); Assert.False(array.IsAtEnd()); } }
private static ByteArrayInputBytes StringToBytes(string str) => new ByteArrayInputBytes(OtherEncodings.StringAsLatin1Bytes(str));
public bool TryTokenize(byte currentByte, IInputBytes inputBytes, out IToken token) { var builder = new StringBuilder(); token = null; if (inputBytes == null) { return(false); } if (currentByte != '(') { return(false); } var numberOfBrackets = 1; var isEscapeActive = false; var isLineBreaking = false; var octalModeActive = false; short[] octal = { 0, 0, 0 }; var octalsRead = 0; while (inputBytes.MoveNext()) { var b = inputBytes.CurrentByte; var c = (char)b; if (octalModeActive) { var nextCharacterOctal = c >= '0' && c <= '7'; if (nextCharacterOctal) { // left shift the octals. LeftShiftOctal(c, octalsRead, octal); octalsRead++; } if (octalsRead == 3 || !nextCharacterOctal) { var characterCode = OctalHelpers.FromOctalDigits(octal); // For now :( // TODO: I have a sneaking suspicion this is wrong, not sure what behaviour is for large octal numbers builder.Append((char)characterCode); octal[0] = 0; octal[1] = 0; octal[2] = 0; octalsRead = 0; octalModeActive = false; } if (nextCharacterOctal) { continue; } } switch (c) { case ')': isLineBreaking = false; if (!isEscapeActive) { numberOfBrackets--; } isEscapeActive = false; if (numberOfBrackets > 0) { builder.Append(c); } // TODO: Check for other ends of string where the string is improperly formatted. See commented method numberOfBrackets = CheckForEndOfString(numberOfBrackets, inputBytes); break; case '(': isLineBreaking = false; if (!isEscapeActive) { numberOfBrackets++; } isEscapeActive = false; builder.Append(c); break; // Escape case '\\': isLineBreaking = false; // Escaped backslash if (isEscapeActive) { builder.Append(c); isEscapeActive = false; } else { isEscapeActive = true; } break; default: if (isLineBreaking) { if (ReadHelper.IsEndOfLine(c)) { continue; } isLineBreaking = false; builder.Append(c); } else if (isEscapeActive) { ProcessEscapedCharacter(c, builder, octal, ref octalModeActive, ref octalsRead, ref isLineBreaking); isEscapeActive = false; } else { builder.Append(c); } break; } if (numberOfBrackets <= 0) { break; } } StringToken.Encoding encodedWith; string tokenStr; if (builder.Length >= 2) { if (builder[0] == 0xFE && builder[1] == 0xFF) { var rawBytes = OtherEncodings.StringAsLatin1Bytes(builder.ToString()); tokenStr = Encoding.BigEndianUnicode.GetString(rawBytes).Substring(1); encodedWith = StringToken.Encoding.Utf16BE; } else if (builder[0] == 0xFF && builder[1] == 0xFE) { var rawBytes = OtherEncodings.StringAsLatin1Bytes(builder.ToString()); tokenStr = Encoding.Unicode.GetString(rawBytes).Substring(1); encodedWith = StringToken.Encoding.Utf16; } else { tokenStr = builder.ToString(); encodedWith = StringToken.Encoding.Iso88591; } } else { tokenStr = builder.ToString(); encodedWith = StringToken.Encoding.Iso88591; } token = new StringToken(tokenStr, encodedWith); return(true); }
public void BytesEmptyReturnsEmptyString() { var result = OtherEncodings.BytesAsLatin1String(new byte[0]); Assert.Equal(string.Empty, result); }
public void Run(IOperationContext operationContext, IResourceStore resourceStore) { var input = new ByteArrayInputBytes(Text != null ? OtherEncodings.StringAsLatin1Bytes(Text) : Bytes); operationContext.ShowText(input); }
public static void WriteCrossReferenceTable(IReadOnlyDictionary <IndirectReference, long> objectOffsets, ObjectToken catalogToken, Stream outputStream) { if (objectOffsets.Count == 0) { throw new InvalidOperationException("Could not write empty cross reference table."); } WriteLineBreak(outputStream); var position = outputStream.Position; outputStream.Write(Xref, 0, Xref.Length); WriteLineBreak(outputStream); var min = objectOffsets.Min(x => x.Key.ObjectNumber); var max = objectOffsets.Max(x => x.Key.ObjectNumber); if (max - min != objectOffsets.Count - 1) { throw new NotSupportedException("Object numbers must form a contiguous range"); } WriteLong(min, outputStream); WriteWhitespace(outputStream); WriteLong(max, outputStream); WriteWhitespace(outputStream); WriteLineBreak(outputStream); foreach (var keyValuePair in objectOffsets.OrderBy(x => x.Key.ObjectNumber)) { /* * nnnnnnnnnn ggggg n eol * where: * nnnnnnnnnn is a 10-digit byte offset * ggggg is a 5-digit generation number * n is a literal keyword identifying this as an in-use entry * eol is a 2-character end-of-line sequence ('\r\n' or ' \n') */ var paddedOffset = OtherEncodings.StringAsLatin1Bytes(keyValuePair.Value.ToString("D10")); outputStream.Write(paddedOffset, 0, paddedOffset.Length); WriteWhitespace(outputStream); var generation = OtherEncodings.StringAsLatin1Bytes(keyValuePair.Key.Generation.ToString("D5")); outputStream.Write(generation, 0, generation.Length); WriteWhitespace(outputStream); outputStream.WriteByte(InUseEntry); WriteWhitespace(outputStream); WriteLineBreak(outputStream); } outputStream.Write(Trailer, 0, Trailer.Length); WriteLineBreak(outputStream); var trailerDictionary = new DictionaryToken(new Dictionary <IToken, IToken> { { NameToken.Size, new NumericToken(objectOffsets.Count) }, { NameToken.Root, new IndirectReferenceToken(catalogToken.Number) } }); WriteDictionary(trailerDictionary, outputStream); WriteLineBreak(outputStream); outputStream.Write(StartXref, 0, StartXref.Length); WriteLineBreak(outputStream); WriteLong(position, outputStream); WriteLineBreak(outputStream); // Complete! outputStream.Write(Eof, 0, Eof.Length); }
public EncryptionHandler(EncryptionDictionary encryptionDictionary, TrailerDictionary trailerDictionary, IReadOnlyList <string> passwords) { this.encryptionDictionary = encryptionDictionary; passwords = passwords ?? new[] { string.Empty }; if (!passwords.Contains(string.Empty)) { passwords = new List <string>(passwords) { string.Empty }; } byte[] documentIdBytes; if (trailerDictionary.Identifier != null && trailerDictionary.Identifier.Count == 2) { var token = trailerDictionary.Identifier[0]; switch (token) { case HexToken hex: documentIdBytes = hex.Bytes.ToArray(); break; default: documentIdBytes = OtherEncodings.StringAsLatin1Bytes(token.Data); break; } } else { documentIdBytes = EmptyArray <byte> .Instance; } if (encryptionDictionary == null) { return; } useAes = false; if (encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.SecurityHandlerInDocument || encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.SecurityHandlerInDocument256) { if (!encryptionDictionary.TryGetCryptHandler(out var cryptHandlerLocal)) { throw new PdfDocumentEncryptedException("Document encrypted with security handler in document but no crypt dictionary found.", encryptionDictionary); } cryptHandler = cryptHandlerLocal; useAes = cryptHandlerLocal?.StreamDictionary?.Name == CryptDictionary.Method.AesV2 || cryptHandlerLocal?.StreamDictionary?.Name == CryptDictionary.Method.AesV3; } var charset = OtherEncodings.Iso88591; if (encryptionDictionary.Revision == 5 || encryptionDictionary.Revision == 6) { // ReSharper disable once RedundantAssignment charset = Encoding.UTF8; } var length = encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.Rc4OrAes40BitKey ? 5 : encryptionDictionary.KeyLength.GetValueOrDefault() / 8; var foundPassword = false; foreach (var password in passwords) { var passwordBytes = charset.GetBytes(password); var isUserPassword = false; byte[] decryptionPasswordBytes; if (IsOwnerPassword(passwordBytes, encryptionDictionary, length, documentIdBytes, out var userPassBytes)) { if (encryptionDictionary.Revision == 5 || encryptionDictionary.Revision == 6) { decryptionPasswordBytes = passwordBytes; } else { decryptionPasswordBytes = userPassBytes; } } else if (IsUserPassword(passwordBytes, encryptionDictionary, length, documentIdBytes)) { decryptionPasswordBytes = passwordBytes; isUserPassword = true; } else { continue; } encryptionKey = CalculateEncryptionKey(decryptionPasswordBytes, encryptionDictionary, length, documentIdBytes, isUserPassword); foundPassword = true; break; } if (!foundPassword) { throw new PdfDocumentEncryptedException("The document was encrypted and none of the provided passwords were the user or owner password.", encryptionDictionary); } }
/// <summary> /// Writes a valid single section cross-reference (xref) table plus trailer dictionary to the output for the set of object offsets. /// </summary> /// <param name="objectOffsets">The byte offset from the start of the document for each object in the document.</param> /// <param name="catalogToken">The object representing the catalog dictionary which is referenced from the trailer dictionary.</param> /// <param name="outputStream">The output stream to write to.</param> /// <param name="documentInformationReference">The object reference for the document information dictionary if present.</param> internal static void WriteCrossReferenceTable(IReadOnlyDictionary <IndirectReference, long> objectOffsets, IndirectReference catalogToken, Stream outputStream, IndirectReference?documentInformationReference) { if (objectOffsets.Count == 0) { throw new InvalidOperationException("Could not write empty cross reference table."); } WriteLineBreak(outputStream); var position = outputStream.Position; outputStream.Write(Xref, 0, Xref.Length); WriteLineBreak(outputStream); var sets = new List <XrefSeries>(); var orderedList = objectOffsets.OrderBy(x => x.Key.ObjectNumber).ToList(); long firstObjectNumber = 0; long currentObjNum = 0; var items = new List <XrefSeries.OffsetAndGeneration> { // Zero entry null }; foreach (var item in orderedList) { var step = item.Key.ObjectNumber - currentObjNum; if (step == 1) { currentObjNum = item.Key.ObjectNumber; items.Add(new XrefSeries.OffsetAndGeneration(item.Value, item.Key.Generation)); } else { sets.Add(new XrefSeries(firstObjectNumber, items)); items = new List <XrefSeries.OffsetAndGeneration> { new XrefSeries.OffsetAndGeneration(item.Value, item.Key.Generation) }; currentObjNum = item.Key.ObjectNumber; firstObjectNumber = item.Key.ObjectNumber; } } if (items.Count > 0) { sets.Add(new XrefSeries(firstObjectNumber, items)); } foreach (var series in sets) { WriteLong(series.First, outputStream); WriteWhitespace(outputStream); WriteLong(series.Offsets.Count, outputStream); WriteWhitespace(outputStream); WriteLineBreak(outputStream); foreach (var offset in series.Offsets) { if (offset != null) { /* * nnnnnnnnnn ggggg n eol * where: * nnnnnnnnnn is a 10-digit byte offset * ggggg is a 5-digit generation number * n is a literal keyword identifying this as an in-use entry * eol is a 2-character end-of-line sequence ('\r\n' or ' \n') */ var paddedOffset = OtherEncodings.StringAsLatin1Bytes(offset.Offset.ToString("D10", CultureInfo.InvariantCulture)); outputStream.Write(paddedOffset, 0, paddedOffset.Length); WriteWhitespace(outputStream); var generation = OtherEncodings.StringAsLatin1Bytes(offset.Generation.ToString("D5", CultureInfo.InvariantCulture)); outputStream.Write(generation, 0, generation.Length); WriteWhitespace(outputStream); outputStream.WriteByte(InUseEntry); WriteWhitespace(outputStream); WriteLineBreak(outputStream); } else { WriteFirstXrefEmptyEntry(outputStream); } } } outputStream.Write(Trailer, 0, Trailer.Length); WriteLineBreak(outputStream); var identifier = new ArrayToken(new IToken[] { new HexToken(Guid.NewGuid().ToString("N").ToCharArray()), new HexToken(Guid.NewGuid().ToString("N").ToCharArray()) }); var trailerDictionaryData = new Dictionary <NameToken, IToken> { // 1 for the free entry. { NameToken.Size, new NumericToken(objectOffsets.Count + 1) }, { NameToken.Root, new IndirectReferenceToken(catalogToken) }, { NameToken.Id, identifier } }; if (documentInformationReference.HasValue) { trailerDictionaryData[NameToken.Info] = new IndirectReferenceToken(documentInformationReference.Value); } var trailerDictionary = new DictionaryToken(trailerDictionaryData); WriteDictionary(trailerDictionary, outputStream); WriteLineBreak(outputStream); outputStream.Write(StartXref, 0, StartXref.Length); WriteLineBreak(outputStream); WriteLong(position, outputStream); WriteLineBreak(outputStream); // Complete! outputStream.Write(Eof, 0, Eof.Length); }
public COSArray Parse(IRandomAccessRead reader, CosBaseParser baseParser, CosObjectPool pool) { ReadHelper.ReadExpectedChar(reader, '['); var po = new COSArray(); CosBase pbo; ReadHelper.SkipSpaces(reader); int i; while (((i = reader.Peek()) > 0) && ((char)i != ']')) { pbo = baseParser.Parse(reader, pool); if (pbo is CosObject) { // We have to check if the expected values are there or not PDFBOX-385 if (po.get(po.size() - 1) is CosInt) { var genNumber = (CosInt)po.remove(po.size() - 1); if (po.get(po.size() - 1) is CosInt) { var number = (CosInt)po.remove(po.size() - 1); CosObjectKey key = new CosObjectKey(number.AsLong(), genNumber.AsInt()); pbo = pool.Get(key); } else { // the object reference is somehow wrong pbo = null; } } else { pbo = null; } } if (pbo != null) { po.add(pbo); } else { //it could be a bad object in the array which is just skipped // LOG.warn("Corrupt object reference at offset " + seqSource.getPosition()); // This could also be an "endobj" or "endstream" which means we can assume that // the array has ended. string isThisTheEnd = ReadHelper.ReadString(reader); reader.Unread(OtherEncodings.StringAsLatin1Bytes(isThisTheEnd)); if (string.Equals(isThisTheEnd, "endobj") || string.Equals(isThisTheEnd, "endstream")) { return(po); } } ReadHelper.SkipSpaces(reader); } // read ']' reader.Read(); ReadHelper.SkipSpaces(reader); return(po); }
public void BytesNullReturnsNullString() { var result = OtherEncodings.BytesAsLatin1String(null); Assert.Null(result); }
public void StringNullReturnsNullBytes() { var result = OtherEncodings.StringAsLatin1Bytes(null); Assert.Null(result); }
/// <summary> /// Writes a valid single section cross-reference (xref) table plus trailer dictionary to the output for the set of object offsets. /// </summary> /// <param name="objectOffsets">The byte offset from the start of the document for each object in the document.</param> /// <param name="catalogToken">The object representing the catalog dictionary which is referenced from the trailer dictionary.</param> /// <param name="outputStream">The output stream to write to.</param> /// <param name="documentInformationReference">The object reference for the document information dictionary if present.</param> internal static void WriteCrossReferenceTable(IReadOnlyDictionary <IndirectReference, long> objectOffsets, ObjectToken catalogToken, Stream outputStream, IndirectReference?documentInformationReference) { if (objectOffsets.Count == 0) { throw new InvalidOperationException("Could not write empty cross reference table."); } WriteLineBreak(outputStream); var position = outputStream.Position; outputStream.Write(Xref, 0, Xref.Length); WriteLineBreak(outputStream); var min = objectOffsets.Min(x => x.Key.ObjectNumber); var max = objectOffsets.Max(x => x.Key.ObjectNumber); if (max - min != objectOffsets.Count - 1) { throw new NotSupportedException("Object numbers must form a contiguous range"); } WriteLong(0, outputStream); WriteWhitespace(outputStream); // 1 extra for the free entry. WriteLong(objectOffsets.Count + 1, outputStream); WriteWhitespace(outputStream); WriteLineBreak(outputStream); WriteFirstXrefEmptyEntry(outputStream); foreach (var keyValuePair in objectOffsets.OrderBy(x => x.Key.ObjectNumber)) { /* * nnnnnnnnnn ggggg n eol * where: * nnnnnnnnnn is a 10-digit byte offset * ggggg is a 5-digit generation number * n is a literal keyword identifying this as an in-use entry * eol is a 2-character end-of-line sequence ('\r\n' or ' \n') */ var paddedOffset = OtherEncodings.StringAsLatin1Bytes(keyValuePair.Value.ToString("D10")); outputStream.Write(paddedOffset, 0, paddedOffset.Length); WriteWhitespace(outputStream); var generation = OtherEncodings.StringAsLatin1Bytes(keyValuePair.Key.Generation.ToString("D5")); outputStream.Write(generation, 0, generation.Length); WriteWhitespace(outputStream); outputStream.WriteByte(InUseEntry); WriteWhitespace(outputStream); WriteLineBreak(outputStream); } outputStream.Write(Trailer, 0, Trailer.Length); WriteLineBreak(outputStream); var identifier = new ArrayToken(new IToken[] { new HexToken(Guid.NewGuid().ToString("N").ToCharArray()), new HexToken(Guid.NewGuid().ToString("N").ToCharArray()) }); var trailerDictionaryData = new Dictionary <NameToken, IToken> { // 1 for the free entry. { NameToken.Size, new NumericToken(objectOffsets.Count + 1) }, { NameToken.Root, new IndirectReferenceToken(catalogToken.Number) }, { NameToken.Id, identifier } }; if (documentInformationReference.HasValue) { trailerDictionaryData[NameToken.Info] = new IndirectReferenceToken(documentInformationReference.Value); } var trailerDictionary = new DictionaryToken(trailerDictionaryData); WriteDictionary(trailerDictionary, outputStream); WriteLineBreak(outputStream); outputStream.Write(StartXref, 0, StartXref.Length); WriteLineBreak(outputStream); WriteLong(position, outputStream); WriteLineBreak(outputStream); // Complete! outputStream.Write(Eof, 0, Eof.Length); }
private IToken DecryptInternal(IndirectReference reference, IToken token) { switch (token) { case StreamToken stream: { if (cryptHandler?.StreamDictionary?.IsIdentity == true || cryptHandler?.StreamDictionary?.Name == CryptDictionary.Method.None) { // TODO: No idea if this is right. return(token); } if (stream.StreamDictionary.TryGet(NameToken.Type, out NameToken typeName)) { if (NameToken.Xref.Equals(typeName)) { return(token); } if (!encryptionDictionary.EncryptMetadata && NameToken.Metadata.Equals(typeName)) { return(token); } // TODO: check unencrypted metadata } var streamDictionary = (DictionaryToken)DecryptInternal(reference, stream.StreamDictionary); var decrypted = DecryptData(stream.Data.ToArray(), reference); token = new StreamToken(streamDictionary, decrypted); break; } case StringToken stringToken: { if (cryptHandler?.StringDictionary?.IsIdentity == true || cryptHandler?.StringDictionary?.Name == CryptDictionary.Method.None) { // TODO: No idea if this is right. return(token); } var data = OtherEncodings.StringAsLatin1Bytes(stringToken.Data); var decrypted = DecryptData(data, reference); token = new StringToken(OtherEncodings.BytesAsLatin1String(decrypted)); break; } case HexToken hexToken: { var data = hexToken.Bytes.ToArray(); var decrypted = DecryptData(data, reference); token = new HexToken(Hex.GetString(decrypted).ToCharArray()); break; } case DictionaryToken dictionary: { // PDFBOX-2936: avoid orphan /CF dictionaries found in US govt "I-" files if (dictionary.TryGet(NameToken.Cf, out _)) { return(token); } var isSignatureDictionary = dictionary.TryGet(NameToken.Type, out NameToken typeName) && (typeName.Equals(NameToken.Sig) || typeName.Equals(NameToken.DocTimeStamp)); foreach (var keyValuePair in dictionary.Data) { if (isSignatureDictionary && keyValuePair.Key == NameToken.Contents.Data) { continue; } if (keyValuePair.Value is StringToken || keyValuePair.Value is ArrayToken || keyValuePair.Value is DictionaryToken) { var inner = DecryptInternal(reference, keyValuePair.Value); dictionary = dictionary.With(keyValuePair.Key, inner); } } token = dictionary; break; } case ArrayToken array: { var result = new IToken[array.Length]; for (var i = 0; i < array.Length; i++) { result[i] = DecryptInternal(reference, array.Data[i]); } token = new ArrayToken(result); break; } } return(token); }
private static void WriteLong(long value, Stream outputStream) { var bytes = OtherEncodings.StringAsLatin1Bytes(value.ToString("G", CultureInfo.InvariantCulture)); outputStream.Write(bytes, 0, bytes.Length); }
public EncryptionHandler(EncryptionDictionary encryptionDictionary, TrailerDictionary trailerDictionary, string password) { this.encryptionDictionary = encryptionDictionary; var documentIdBytes = trailerDictionary.Identifier != null && trailerDictionary.Identifier.Count == 2 ? OtherEncodings.StringAsLatin1Bytes(trailerDictionary.Identifier[0]) : EmptyArray <byte> .Instance; password = password ?? string.Empty; if (encryptionDictionary == null) { return; } useAes = false; if (encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.SecurityHandlerInDocument || encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.SecurityHandlerInDocument256) { if (!encryptionDictionary.TryGetCryptHandler(out var cryptHandlerLocal)) { throw new PdfDocumentEncryptedException("Document encrypted with security handler in document but no crypt dictionary found.", encryptionDictionary); } cryptHandler = cryptHandlerLocal; useAes = cryptHandlerLocal?.StreamDictionary?.Name == CryptDictionary.Method.AesV2 || cryptHandlerLocal?.StreamDictionary?.Name == CryptDictionary.Method.AesV3; } var charset = OtherEncodings.Iso88591; if (encryptionDictionary.Revision == 5 || encryptionDictionary.Revision == 6) { // ReSharper disable once RedundantAssignment charset = Encoding.UTF8; } var passwordBytes = charset.GetBytes(password); byte[] decryptionPasswordBytes; var length = encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.Rc4OrAes40BitKey ? 5 : encryptionDictionary.KeyLength.GetValueOrDefault() / 8; var isUserPassword = false; if (IsOwnerPassword(passwordBytes, encryptionDictionary, length, documentIdBytes, out var userPassBytes)) { if (encryptionDictionary.Revision == 5 || encryptionDictionary.Revision == 6) { decryptionPasswordBytes = passwordBytes; } else { decryptionPasswordBytes = userPassBytes; } } else if (IsUserPassword(passwordBytes, encryptionDictionary, length, documentIdBytes)) { decryptionPasswordBytes = passwordBytes; isUserPassword = true; } else { throw new PdfDocumentEncryptedException("The document was encrypted and the provided password was neither the user or owner password.", encryptionDictionary); } encryptionKey = CalculateEncryptionKey(decryptionPasswordBytes, encryptionDictionary, length, documentIdBytes, isUserPassword); }
public IReadOnlyDictionary <CosObjectKey, long> GetObjectLocations() { if (objectLocations != null) { return(objectLocations); } var lastEndOfFile = GetLastEndOfFileMarker(); var results = new Dictionary <CosObjectKey, long>(); var originPosition = reader.GetPosition(); long currentOffset = MinimumSearchOffset; long lastObjectId = long.MinValue; int lastGenerationId = int.MinValue; long lastObjOffset = long.MinValue; byte[] objString = OtherEncodings.StringAsLatin1Bytes(" obj"); byte[] endobjString = OtherEncodings.StringAsLatin1Bytes("endobj"); bool endobjFound = false; do { reader.Seek(currentOffset); if (ReadHelper.IsString(reader, objString)) { long tempOffset = currentOffset - 1; reader.Seek(tempOffset); int generationId = reader.Peek(); // is the next char a digit? if (ReadHelper.IsDigit(generationId)) { generationId -= 48; tempOffset--; reader.Seek(tempOffset); if (ReadHelper.IsSpace(reader)) { while (tempOffset > MinimumSearchOffset && ReadHelper.IsSpace(reader)) { reader.Seek(--tempOffset); } bool objectIdFound = false; while (tempOffset > MinimumSearchOffset && ReadHelper.IsDigit(reader)) { reader.Seek(--tempOffset); objectIdFound = true; } if (objectIdFound) { reader.Read(); long objectId = ObjectHelper.ReadObjectNumber(reader); if (lastObjOffset > 0) { // add the former object ID only if there was a subsequent object ID results[new CosObjectKey(lastObjectId, lastGenerationId)] = lastObjOffset; } lastObjectId = objectId; lastGenerationId = generationId; lastObjOffset = tempOffset + 1; currentOffset += objString.Length - 1; endobjFound = false; } } } } else if (ReadHelper.IsString(reader, "endobj")) { endobjFound = true; currentOffset += endobjString.Length - 1; } currentOffset++; } while (currentOffset < lastEndOfFile && !reader.IsEof()); if ((lastEndOfFile < long.MaxValue || endobjFound) && lastObjOffset > 0) { // if the pdf wasn't cut off in the middle or if the last object ends with a "endobj" marker // the last object id has to be added here so that it can't get lost as there isn't any subsequent object id results[new CosObjectKey(lastObjectId, lastGenerationId)] = lastObjOffset; } // reestablish origin position reader.Seek(originPosition); objectLocations = results; return(objectLocations); }
public CosBase Parse(IRandomAccessRead reader, CosObjectPool pool) { CosBase retval = null; ReadHelper.SkipSpaces(reader); int nextByte = reader.Peek(); if (nextByte == -1) { return(null); } char c = (char)nextByte; switch (c) { case '<': { // pull off first left bracket int leftBracket = reader.Read(); // check for second left bracket c = (char)reader.Peek(); reader.Unread(leftBracket); if (c == '<') { retval = dictionaryParser.Parse(reader, this, pool); ReadHelper.SkipSpaces(reader); } else { retval = stringParser.Parse(reader); } break; } case '[': { // array retval = arrayParser.Parse(reader, this, pool); break; } case '(': retval = stringParser.Parse(reader); break; case '/': // name retval = nameParser.Parse(reader); break; case 'n': { // null ReadHelper.ReadExpectedString(reader, "null"); retval = CosNull.Null; break; } case 't': { string truestring = OtherEncodings.BytesAsLatin1String(reader.ReadFully(4)); if (truestring.Equals("true")) { retval = PdfBoolean.True; } else { throw new IOException("expected true actual='" + truestring + "' " + reader + "' at offset " + reader.GetPosition()); } break; } case 'f': { string falsestring = OtherEncodings.BytesAsLatin1String(reader.ReadFully(5)); if (falsestring.Equals("false")) { retval = PdfBoolean.False; } else { throw new IOException("expected false actual='" + falsestring + "' " + reader + "' at offset " + reader.GetPosition()); } break; } case 'R': reader.Read(); retval = new CosObject(null); break; default: if (char.IsDigit(c) || c == '-' || c == '+' || c == '.') { StringBuilder buf = new StringBuilder(); int ic = reader.Read(); c = (char)ic; while (char.IsDigit(c) || c == '-' || c == '+' || c == '.' || c == 'E' || c == 'e') { buf.Append(c); ic = reader.Read(); c = (char)ic; } if (ic != -1) { reader.Unread(ic); } retval = CosNumberFactory.get(buf.ToString()) as CosBase; } else { //This is not suppose to happen, but we will allow for it //so we are more compatible with POS writers that don't //follow the spec string badstring = ReadHelper.ReadString(reader); if (badstring == string.Empty) { int peek = reader.Peek(); // we can end up in an infinite loop otherwise throw new IOException("Unknown dir object c='" + c + "' cInt=" + (int)c + " peek='" + (char)peek + "' peekInt=" + peek + " at offset " + reader.GetPosition()); } // if it's an endstream/endobj, we want to put it back so the caller will see it if (string.Equals("endobj", badstring) || string.Equals("endstream", badstring)) { reader.Unread(OtherEncodings.StringAsLatin1Bytes(badstring)); } } break; } return(retval); }