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); } } }