001/*
002 *  Copyright (c) 2023-2026, Agents-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.agentsflex.core.file2text.extractor.impl;
017
018import com.agentsflex.core.file2text.extractor.FileExtractor;
019import com.agentsflex.core.file2text.source.DocumentSource;
020import org.apache.poi.hwpf.HWPFDocument;
021import org.apache.poi.hwpf.extractor.WordExtractor;
022import org.apache.poi.poifs.filesystem.POIFSFileSystem;
023
024import java.io.IOException;
025import java.io.InputStream;
026import java.util.Collections;
027import java.util.HashSet;
028import java.util.Set;
029
030/**
031 * DOC 文档提取器(.doc)
032 * 支持旧版 Word 97-2003 格式
033 */
034public class DocExtractor implements FileExtractor {
035
036    private static final Set<String> SUPPORTED_MIME_TYPES;
037    private static final Set<String> SUPPORTED_EXTENSIONS;
038
039    static {
040        Set<String> mimeTypes = new HashSet<>();
041        mimeTypes.add("application/msword");
042        SUPPORTED_MIME_TYPES = Collections.unmodifiableSet(mimeTypes);
043
044        Set<String> extensions = new HashSet<>();
045        extensions.add("doc");
046        extensions.add("dot");
047        SUPPORTED_EXTENSIONS = Collections.unmodifiableSet(extensions);
048    }
049
050    @Override
051    public boolean supports(DocumentSource source) {
052        String mimeType = source.getMimeType();
053        String fileName = source.getFileName();
054
055        if (mimeType != null && SUPPORTED_MIME_TYPES.contains(mimeType)) {
056            return true;
057        }
058
059        if (fileName != null) {
060            String ext = getExtension(fileName);
061            if (ext != null && SUPPORTED_EXTENSIONS.contains(ext.toLowerCase())) {
062                return true;
063            }
064        }
065
066        return false;
067    }
068
069    @Override
070    public String extractText(DocumentSource source) throws IOException {
071        try (InputStream is = source.openStream();
072             POIFSFileSystem fs = new POIFSFileSystem(is);
073             HWPFDocument doc = new HWPFDocument(fs)) {
074
075            WordExtractor extractor = new WordExtractor(doc);
076            String[] paragraphs = extractor.getParagraphText();
077
078            StringBuilder text = new StringBuilder();
079            for (String para : paragraphs) {
080                // 清理控制字符
081                String clean = para.replaceAll("[\\r\\001]+", "").trim();
082                if (!clean.isEmpty()) {
083                    text.append(clean).append("\n");
084                }
085            }
086            return text.toString().trim();
087        } catch (Exception e) {
088            throw new IOException("Failed to extract .doc file: " + e.getMessage(), e);
089        }
090    }
091
092    @Override
093    public int getOrder() {
094        return 15; // 低于 .docx
095    }
096
097    private String getExtension(String fileName) {
098        if (fileName == null || !fileName.contains(".")) return null;
099        int lastDot = fileName.lastIndexOf('.');
100        return fileName.substring(lastDot + 1);
101    }
102}