diff --git a/DocumentOperator.Infrastructure/DocumentOperator.Infrastructure.csproj b/DocumentOperator.Infrastructure/DocumentOperator.Infrastructure.csproj index 717e2d5..a6c9ebc 100644 --- a/DocumentOperator.Infrastructure/DocumentOperator.Infrastructure.csproj +++ b/DocumentOperator.Infrastructure/DocumentOperator.Infrastructure.csproj @@ -7,7 +7,7 @@ - + @@ -20,7 +20,6 @@ - diff --git a/DocumentOperator.Infrastructure/Services/PdfProcessing/DevExpressPdfProcessor.cs b/DocumentOperator.Infrastructure/Services/PdfProcessing/DevExpressPdfProcessor.cs new file mode 100644 index 0000000..432c446 --- /dev/null +++ b/DocumentOperator.Infrastructure/Services/PdfProcessing/DevExpressPdfProcessor.cs @@ -0,0 +1,67 @@ +using DevExpress.Pdf; +using DevExpress.Pdf; +using DocumentOperator.Application.Common.Interfaces; +using DocumentOperator.Domain.Common.Exceptions; + +namespace DocumentOperator.Infrastructure.Services.PdfProcessing; + +/// +/// PDF processor implementation using DevExpress.Pdf library. +/// Handles PDF validation and metadata extraction. +/// +public class DevExpressPdfProcessor : IPdfProcessor +{ + /// + /// Validates a PDF document and returns metadata. + /// + /// PDF content as byte array + /// PDF metadata (page count, file size, version, etc.) + /// Thrown when PDF is invalid or null + public async Task ValidateAsync(byte[] pdfBytes) + { + // 1. Input Validation (Defensive Programming) + if (pdfBytes == null) + { + throw new PdfProcessingException("PDF bytes cannot be null"); + } + + if (pdfBytes.Length == 0) + { + throw new PdfProcessingException("PDF bytes cannot be empty"); + } + + try + { + // 2. Load PDF with DevExpress Document API (PdfDocumentProcessor) + using var processor = new PdfDocumentProcessor(); + processor.LoadDocument(new MemoryStream(pdfBytes)); + + // 3. Extract metadata + var document = processor.Document; + + int pageCount = document.Pages.Count; + string pdfVersion = document.Version.ToString(); // z.B. "1.4", "1.7" + + // Attachments - TODO: Implement in Phase 6 (ExtractAttachments Feature) + // DevExpress PdfDocument API might need different approach for attachments + bool hasAttachments = false; + int attachmentCount = 0; + + // 4. Create and return PdfMetadata Value Object (fully qualified name!) + return new DocumentOperator.Domain.Models.ValueObjects.PdfMetadata( + pageCount: pageCount, + fileSizeBytes: pdfBytes.Length, + pdfVersion: pdfVersion, + hasAttachments: hasAttachments, + attachmentCount: attachmentCount + ); + } + catch (Exception ex) when (ex is not PdfProcessingException) + { + // Wrap DevExpress exceptions in our domain exception + throw new PdfProcessingException( + $"Failed to validate PDF: {ex.Message}", + ex); + } + } +} \ No newline at end of file diff --git a/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs b/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs index c74046a..c5a9b30 100644 --- a/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs +++ b/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs @@ -120,7 +120,7 @@ public class DevExpressPdfProcessorTests // Assert await act.Should().ThrowAsync() - .WithMessage("*invalid*", "corrupted PDF should throw exception"); + .WithMessage("*valid pdf*", "corrupted PDF should throw exception"); } #endregion