From 8962a63cf59a16f444aab493b55484f3b48c678a Mon Sep 17 00:00:00 2001 From: Mustafa Yildiz Date: Sat, 15 Aug 2026 10:43:54 +0300 Subject: [PATCH] fix: upgrade UDF text extraction with multi-offset PK search and binary noise filter --- src/controllers/document.controller.ts | 57 ++++++++++++++++---------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/src/controllers/document.controller.ts b/src/controllers/document.controller.ts index 47c5eb1..78c99fd 100644 --- a/src/controllers/document.controller.ts +++ b/src/controllers/document.controller.ts @@ -421,16 +421,29 @@ export async function extractTextFromUploadedFile(file: { buffer: Buffer; mimety if (fileName.endsWith('.udf')) { try { let zip: AdmZip | null = null; + + // 1. Önce doğrudan buffer üzerinden dene try { zip = new AdmZip(file.buffer); - } catch (e) { - // PK\x03\x04 imzasını (0x50, 0x4B, 0x03, 0x04) buffer içinde ara (UYAP e-imza başlığı olan dosyalar için) + if (zip.getEntries().length === 0) zip = null; + } catch (_) {} + + // 2. Başarısız olursa PK\x03\x04 imzalarını (0x50, 0x4B, 0x03, 0x04) tüm buffer içinde tarayıp geçerli ZIP arşivini bul + if (!zip) { const pkSignature = Buffer.from([0x50, 0x4b, 0x03, 0x04]); - const pkIndex = file.buffer.indexOf(pkSignature); - if (pkIndex > 0) { + let searchOffset = 0; + while (searchOffset < file.buffer.length) { + const pkIndex = file.buffer.indexOf(pkSignature, searchOffset); + if (pkIndex === -1) break; try { - zip = new AdmZip(file.buffer.subarray(pkIndex)); + const testZip = new AdmZip(file.buffer.subarray(pkIndex)); + const entries = testZip.getEntries(); + if (entries && entries.length > 0) { + zip = testZip; + break; + } } catch (_) {} + searchOffset = pkIndex + 1; } } @@ -438,7 +451,7 @@ export async function extractTextFromUploadedFile(file: { buffer: Buffer; mimety const zipEntries = zip.getEntries().filter((e: any) => !e.isDirectory); // 1. Önce XML dosyasını kontrol et (content.xml veya *.xml) - const xmlEntry = zipEntries.find((entry: any) => + const xmlEntries = zipEntries.filter((entry: any) => entry.entryName === "content.xml" || entry.entryName.toLowerCase().endsWith(".xml") ); @@ -447,16 +460,11 @@ export async function extractTextFromUploadedFile(file: { buffer: Buffer; mimety entry.entryName.toLowerCase().endsWith(".pdf") ); - // Eğer XML bulunmuşsa XML üzerinden devam et - if (xmlEntry) { + for (const xmlEntry of xmlEntries) { let rawXml = ''; try { const entryBuffer = xmlEntry.getData(); - // UDF belgeleri UTF-8 veya ISO-8859-9 / Windows-1254 (Türkçe) kodlamasına sahip olabilir rawXml = entryBuffer.toString('utf8'); - if (rawXml.includes('encoding="ISO-8859-9"') || rawXml.includes('encoding="windows-1254"')) { - // iconv-lite or fallback string replacement if needed - } } catch (_) { rawXml = zip.readAsText(xmlEntry); } @@ -469,8 +477,10 @@ export async function extractTextFromUploadedFile(file: { buffer: Buffer; mimety .replace(/ /g, " ") .replace(/\s+/g, " ") .trim(); - if (plainText.length > 20) { - return sanitizePostgresText(plainText); + + const cleaned = sanitizePostgresText(plainText); + if (cleaned.length > 20 && !cleaned.startsWith('PK')) { + return cleaned; } } } @@ -486,20 +496,25 @@ export async function extractTextFromUploadedFile(file: { buffer: Buffer; mimety } } - // ZIP çözülemediyse düz XML / metin olarak oku + // 3. ZIP çözülemediyse ham buffer içinden okunabilir Türkçe metin bloklarını çek (İkili çöp veriyi süz) const rawText = file.buffer.toString('utf8'); - if (rawText && rawText.trim().length > 20) { - const plainText = rawText.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim(); - const cleaned = sanitizePostgresText(plainText); - if (cleaned.length > 20) { + const textMatches = rawText.match(/[a-zA-Z0-9çğıöşüÇĞİÖŞÜ\s.,:;()\-]{15,}/g); + if (textMatches && textMatches.length > 0) { + const cleanExtracted = textMatches + .map(m => m.trim()) + .filter(m => m.length > 15 && !m.includes('documentproperties') && !m.includes('sign.sgn') && !m.startsWith('PK')) + .join('\n'); + + const cleaned = sanitizePostgresText(cleanExtracted); + if (cleaned.length > 30) { return cleaned; } } - throw new Error("UDF/ZIP arşivinde okunabilir XML veya PDF içeriği bulunamadı."); + throw new Error("UDF arşivinde okunabilir metin içeriği bulunamadı."); } catch (err: any) { console.error("UDF parse error:", err); - throw new Error(`UDF dosyası ayrıştırılamadı: ${err.message || 'Bozuk arşiv'}`); + throw new Error(`UDF dosyası ayrıştırılamadı: ${err.message || 'Bozuk veya şifreli dosya'}`); } }