Blob Blame History Raw
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */

/* libmwaw
* Version: MPL 2.0 / LGPLv2+
*
* The contents of this file are subject to the Mozilla Public License Version
* 2.0 (the "License"); you may not use this file except in compliance with
* the License or as specified alternatively below. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Major Contributor(s):
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
* Copyright (C) 2006, 2007 Andrew Ziem
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
*
*
* All Rights Reserved.
*
* For minor contributions see the git repository.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
* in which case the provisions of the LGPLv2+ are applicable
* instead of those above.
*/

/** \file MWAWHeader.cxx
 * Implements MWAWHeader (document's type, version, kind)
 */

#include <string.h>
#include <iostream>

#include "libmwaw_internal.hxx"

#include "MWAWEntry.hxx"
#include "MWAWInputStream.hxx"
#include "MWAWRSRCParser.hxx"

#include "MWAWHeader.hxx"

MWAWHeader::MWAWHeader(MWAWDocument::Type documentType, int vers, MWAWDocument::Kind kind)
  : m_version(vers)
  , m_docType(documentType)
  , m_docKind(kind)
{
}

MWAWHeader::~MWAWHeader()
{
}

/**
 * So far, we have identified
 */
std::vector<MWAWHeader> MWAWHeader::constructHeader
(MWAWInputStreamPtr input, std::shared_ptr<MWAWRSRCParser> /*rsrcParser*/)
{
  std::vector<MWAWHeader> res;
  if (!input) return res;
  // ------------ first check finder info -------------
  std::string type, creator;
  if (input->getFinderInfo(type, creator)) {
    // set basic version, the correct will be filled by check header
    if (creator=="ACTA") {
      if (type=="OTLN") { // at least basic v2
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_ACTA, 1));
        return res;
      }
      else if (type=="otln") {   // classic version
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_ACTA, 2));
        return res;
      }
    }
    else if (creator=="BOBO") {
      if (type=="CWDB" || type=="CWD2" || type=="sWDB") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISWORKS, 1, MWAWDocument::MWAW_K_DATABASE));
        return res;
      }
      if (type=="CWGR" || type=="sWGR") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISWORKS, 1, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
      if (type=="CWSS" || type=="CWS2" || type=="sWSS") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISWORKS, 1, MWAWDocument::MWAW_K_SPREADSHEET));
        return res;
      }
      if (type=="CWPR") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISWORKS, 1, MWAWDocument::MWAW_K_PRESENTATION));
        return res;
      }
      if (type=="CWPT") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISWORKS, 1, MWAWDocument::MWAW_K_PAINT));
        return res;
      }
      if (type=="CWWP" || type=="CWW2" || type=="sWPP") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISWORKS, 1, MWAWDocument::MWAW_K_TEXT));
        return res;
      }
    }
    else if (creator=="BWks") {
      if (type=="BWwp") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_BEAGLEWORKS, 1));
        return res;
      }
      if (type=="BWdb") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_BEAGLEWORKS, 1, MWAWDocument::MWAW_K_DATABASE));
        return res;
      }
      if (type=="BWdr") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_BEAGLEWORKS, 1, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
      if (type=="BWpt") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_BEAGLEWORKS, 1, MWAWDocument::MWAW_K_PAINT));
        return res;
      }
      if (type=="BWss") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_BEAGLEWORKS, 1, MWAWDocument::MWAW_K_SPREADSHEET));
        return res;
      }
    }
    else if (creator=="CDrw") {
      if (type=="dDrw" || type=="dDst" || type=="iLib") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISDRAW, 1, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
    }
    else if (creator=="CRDW") {
      if (type=="CKDT") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CRICKETDRAW, 1, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
    }
    else if (creator=="C#+A") { // solo
      if (type=="C#+D" || type=="C#+F") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_RAGTIME, 5));
        return res;
      }
    }
    else if (creator=="Dc@P" || creator=="Dk@P") {
      if (type=="APPL") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_DOCMAKER, 1));
        return res;
      }
    }
    else if (creator=="FHA2") {
      if (type=="FHD2" || type=="FHT2") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_FREEHAND, 2, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
    }
    else if (creator=="FS03") {
      if (type=="WRT+") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_WRITERPLUS, 1));
        return res;
      }
    }
    else if (creator=="FWRT") {
      if (type=="FWRM") { // 1.7 ?
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_FULLWRITE, 1));
        return res;
      }
      if (type=="FWRT") { // 1.0 ?
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_FULLWRITE, 1));
        return res;
      }
      if (type=="FWRI") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_FULLWRITE,2));
        return res;
      }
    }
    else if (creator=="F#+A") { // Classic
      if (type=="F#+D" || type=="F#+F") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_RAGTIME, 3));
        return res;
      }
    }
    else if (creator=="GM01") {
      if (type=="GfMt") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MOUSEWRITE, 1));
        return res;
      }
    }
    else if (creator=="HMiw") {   // japonese
      if (type=="IWDC") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_HANMACWORDJ,1));
        return res;
      }
    }
    else if (creator=="HMdr") {   // korean
      if (type=="DRD2") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_HANMACWORDK,1));
        return res;
      }
    }
    else if (creator=="LWTE") {
      if (type=="TEXT" || type=="ttro") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_LIGHTWAYTEXT,1));
        return res;
      }
    }
    else if (creator=="LWTR") {
      if (type=="APPL") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_LIGHTWAYTEXT,1));
        return res;
      }
    }
    else if (creator=="MACA") {
      if (type=="WORD") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACWRITE, 1));
        return res;
      }
    }
    else if (creator=="MACD") { // v1.0
      if (type=="DRWG") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAFT, 1, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
    }
    else if (creator=="MAXW") {
      if (type=="MWCT") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MAXWRITE, 1));
        return res;
      }
    }
    else if (creator=="MD40") {
      if (type=="MDDC" || type=="MSYM") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAFT, 4, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
    }
    else if (creator=="MDFT") { // v1.2
      if (type=="DRWG") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAFT, 1, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
    }
    else if (creator=="MDPL") { // MacDraw II
      if (type=="DRWG") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAWPRO, 0, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
      if (type=="STAT") { // stationery
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAWPRO, 0, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
    }
    else if (creator=="MDRW") {
      if (type=="DRWG") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAW, 1, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
    }
    else if (creator=="MDsr") {
      if (type=="APPL") { // auto content
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDOC, 1));
        return res;
      }
    }
    else if (creator=="MDvr") {
      if (type=="MDdc") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDOC, 1));
        return res;
      }
    }
    else if (creator=="MMBB") {
      if (type=="MBBT") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MARINERWRITE, 1));
        return res;
      }
    }
    else if (creator=="MORE") {
      if (type=="MORE") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MORE, 1));
        return res;
      }
    }
    else if (creator=="MOR2") {
      if (type=="MOR2") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MORE, 2));
        return res;
      }
      if (type=="MOR3") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MORE, 3));
        return res;
      }
    }
    else if (creator=="MPNT") {
      if (type=="PNTG") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACPAINT, 1, MWAWDocument::MWAW_K_PAINT));
        return res;
      }
    }
    else if (creator=="MSWD") {
      if (type=="WDBN" || type=="GLOS") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORD, 3));
        return res;
      }
    }
    else if (creator=="MSWK") {
      if (type=="AWWP") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 3));
        return res;
      }
      if (type=="AWDB") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 3, MWAWDocument::MWAW_K_DATABASE));
        return res;
      }
      if (type=="AWDR") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 3, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
      if (type=="AWSS") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 2, MWAWDocument::MWAW_K_SPREADSHEET));
        return res;
      }
      if (type=="RLRB" || type=="sWRB") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 4));
        return res;
      }
    }
    else if (creator=="MWII") {   // MacWriteII
      if (type=="MW2D") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACWRITEPRO, 0));
        return res;
      }
    }
    else if (creator=="MWPR") {
      if (type=="MWPd") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACWRITEPRO, 1));
        return res;
      }
    }
    else if (creator=="NISI") {
      if (type=="TEXT") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_NISUSWRITER, 1));
        return res;
      }
      if (type=="GLOS") { // checkme: glossary, ie. a list of picture/word, keep it ?
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_NISUSWRITER, 1));
        return res;
      }
      // "edtt": empty file, probably created when the file is edited
    }
    else if (creator=="PANT") {
      if (type=="PNTG") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_FULLPAINT, 1, MWAWDocument::MWAW_K_PAINT));
        return res;
      }
    }
    else if (creator=="PLAN") {
      if (type=="MPBN") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTMULTIPLAN, 1, MWAWDocument::MWAW_K_SPREADSHEET));
        return res;
      }
    }
    else if (creator=="PIXR") {
      if (type=="PX01") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_PIXELPAINT, 1, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
    }
    else if (creator=="PPT3") {
      if (type=="SLD3") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_POWERPOINT, 3, MWAWDocument::MWAW_K_PRESENTATION));
        return res;
      }
    }
    else if (creator=="PPNT") {
      if (type=="SLDS") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_POWERPOINT, 2, MWAWDocument::MWAW_K_PRESENTATION));
        return res;
      }
    }
    else if (creator=="PSIP") {
      if (type=="AWWP") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 1));
        return res;
      }
    }
    else if (creator=="PSI2") {
      if (type=="AWWP") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 2));
        return res;
      }
      if (type=="AWDB") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 2, MWAWDocument::MWAW_K_DATABASE));
        return res;
      }
      if (type=="AWSS") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 2, MWAWDocument::MWAW_K_SPREADSHEET));
        return res;
      }
    }
    else if (creator=="PWRI") {
      if (type=="OUTL") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MINDWRITE, 2));
        return res;
      }
    }
    else if (creator=="Rslv") {
      if (type=="RsWs") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISRESOLVE, 1, MWAWDocument::MWAW_K_SPREADSHEET));
        return res;
      }
    }
    else if (creator=="R#+A") {
      if (type=="R#+D" || type=="R#+F") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_RAGTIME, 3));
        return res;
      }
    }
    else if (creator=="SPNT") {
      if (type=="SPTG") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_SUPERPAINT, 1, MWAWDocument::MWAW_K_PAINT));
        return res;
      }
      if (type=="PNTG") {
        // same as MacPaint format, so use the MacPaint parser
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACPAINT, 1, MWAWDocument::MWAW_K_PAINT));
        return res;
      }
      // other type seems to correspond to basic picture file, so we do not accept them
    }
    else if (creator=="StAV") {
      if (type=="APPL") { // Style: document application
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_STYLE, 1));
        return res;
      }
    }
    else if (creator==std::string("St")+char(0xd8)+"l") { //  argh, not standart character
      std::string type1=std::string("TEd")+char(0xb6); // argh, not standart character
      if (type==type1) {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_STYLE, 1));
        return res;
      }
    }
    else if (creator=="TBB5") {
      if (type=="TEXT" || type=="ttro") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_TEXEDIT, 1));
        return res;
      }
    }
    else if (creator=="WNGZ") {
      if (type=="WZSS") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_WINGZ, 1, MWAWDocument::MWAW_K_SPREADSHEET));
        return res;
      }
    }
    else if (creator=="WORD") {
      if (type=="WDBN") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORD, 1));
        return res;
      }
    }
    else if (creator=="ZEBR") {
      if (type=="ZWRT") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_GREATWORKS, 1));
        return res;
      }
      if (type=="ZOBJ") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_GREATWORKS, 1, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
      if (type=="PNTG") {
        // same as MacPaint format, so use the MacPaint parser
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACPAINT, 1, MWAWDocument::MWAW_K_PAINT));
        return res;
      }
      if (type=="ZPNT") {
        /* the ZPNT(v2) are basic pct files with some resources, but
           we treat them to be complete */
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_GREATWORKS, 2, MWAWDocument::MWAW_K_PAINT));
        return res;
      }
      if (type=="ZCAL") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_GREATWORKS, 1, MWAWDocument::MWAW_K_SPREADSHEET));
        return res;
      }
      if (type=="ZDBS") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_GREATWORKS, 1, MWAWDocument::MWAW_K_DATABASE));
        return res;
      }
      // can we treat also ZOLN ?
    }
    else if (creator=="ZWRT") {
      if (type=="Zart") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_ZWRITE, 1));
        return res;
      }
    }
    else if (creator=="aca3") {
      if (type=="acf3" || type=="act3") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_FREEHAND, 1, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
    }
    else if (creator=="dPro") {
      if (type=="dDoc") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAWPRO, 1, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
      if (type=="dLib") { // macdraw pro slide/library
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAWPRO, 1, MWAWDocument::MWAW_K_DRAW));
        return res;
      }
    }
    else if (creator=="eDcR") {
      if (type=="eDoc") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_EDOC, 1));
        return res;
      }
    }
    else if (creator=="eSRD") {   // self reading application
      if (type=="APPL") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_EDOC, 1));
        return res;
      }
    }
    else if (creator=="nX^n") {
      if (type=="nX^d") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_WRITENOW, 2));
        return res;
      }
      if (type=="nX^2") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_WRITENOW, 3));
        return res;
      }
    }
    else if (creator=="ttxt") {
      if (type=="TEXT" || type=="ttro") {
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_TEACHTEXT, 1));
        return res;
      }
    }
    else if (type=="PICT") {
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_APPLEPICT, 1, MWAWDocument::MWAW_K_DRAW));
      return res;
    }
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: unknown finder info: type=%s[%s]\n", type.c_str(), creator.c_str()));

  }

  // ----------- now check resource fork ------------
  // ----------- now check data fork ------------
  if (!input->hasDataFork() || input->size() < 8)
    return res;

  input->seek(0, librevenge::RVNG_SEEK_SET);
  int val[5];
  for (auto &v : val) v = int(input->readULong(2));

  // ----------- clearly discriminant ------------------
  if (val[2] == 0x424F && val[3] == 0x424F && (val[0]>>8) < 7) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a Claris Works file\n"));
    int vers= (val[0] >> 8);
    static int const typePos[7] = {0, 242, 248, 248, 256, 268, 278};
    int typeFile=-1;
    if (vers >= 1 && vers <= 6 && input->checkPosition(typePos[vers])) {
      input->seek(typePos[vers], librevenge::RVNG_SEEK_SET);
      typeFile=int(input->readLong(1));
    }
    switch (typeFile) {
    case 0:
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISWORKS, vers, MWAWDocument::MWAW_K_DRAW));
      return res;
    case 1:
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISWORKS, vers, MWAWDocument::MWAW_K_TEXT));
      return res;
    case 2:
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISWORKS, vers, MWAWDocument::MWAW_K_SPREADSHEET));
      return res;
    case 3:
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISWORKS, vers, MWAWDocument::MWAW_K_DATABASE));
      return res;
    case 4:
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISWORKS, vers, MWAWDocument::MWAW_K_PAINT));
      return res;
    case 5:
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISWORKS, vers, MWAWDocument::MWAW_K_PRESENTATION));
      return res;
    default:
      break;
    }
  }
  if (val[0]==0x5772 && val[1]==0x6974 && val[2]==0x654e && val[3]==0x6f77) {
    input->seek(8, librevenge::RVNG_SEEK_SET);
    auto version = int(input->readLong(2));

#ifdef DEBUG
    bool ok = (version >= 0 && version <= 3);
    if (ok)
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a WriteNow file version 3.0 or 4.0\n"));
    else
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a WriteNow file (unknown version %d)\n", version));
#else
    bool ok = version == 2;
#endif

    if (ok) {
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_WRITENOW, 3));
      return res;
    }
  }
  if (val[0]==0x574e && val[1]==0x475a && val[2]==0x575a && val[3]==0x5353) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a Wingz file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_WINGZ, 1, MWAWDocument::MWAW_K_SPREADSHEET));
    return res;
  }
  if (val[0]==0x4241 && val[1]==0x545F && val[2]==0x4254 && val[3]==0x5353) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a ClarisResolve file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISRESOLVE, 1, MWAWDocument::MWAW_K_SPREADSHEET));
    return res;
  }
  if (val[0]==0x4323 && val[1]==0x2b44 && val[2]==0xa443 && val[3]==0x4da5) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a RagTime 5-6 file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_RAGTIME, 5));
    return res;
  }
  if (val[0]==0x4646 && val[1]==0x4646 && val[2]==0x3030 && val[3]==0x3030) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a Mariner Write file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MARINERWRITE, 1));
    return res;
  }
  if (val[0]==0x4257 && val[1]==0x6b73 && val[2]==0x4257) {
    if (val[3]==0x7770) {
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a BeagleWorks file\n"));
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_BEAGLEWORKS, 1));
      return res;
    }
    if (val[3]==0x6462) {
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a BeagleWorks Database file\n"));
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_BEAGLEWORKS, 1, MWAWDocument::MWAW_K_DATABASE));
      return res;
    }
    if (val[3]==0x6472) {
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a BeagleWorks Draw file\n"));
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_BEAGLEWORKS, 1, MWAWDocument::MWAW_K_DRAW));
      return res;
    }
    if (val[3]==0x7074) {
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a BeagleWorks Paint file\n"));
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_BEAGLEWORKS, 1, MWAWDocument::MWAW_K_PAINT));
      return res;
    }
    if (val[3]==0x7373) {
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a BeagleWorks Spreadsheet file\n"));
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_BEAGLEWORKS, 1, MWAWDocument::MWAW_K_SPREADSHEET));
      return res;
    }
  }
  if (val[0]==0x4452 && val[1]==0x5747) { // DRWG
    if (val[2]==0x4d44) { // MD
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a MacDraw file\n"));
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAW, 1, MWAWDocument::MWAW_K_DRAW));
      return res;
    }
    if (val[2]==0 || val[2]==0x4432) { // D2
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a MacDraw II file\n"));
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAWPRO, 0, MWAWDocument::MWAW_K_DRAW));
      // can also be a classic apple pict, so let's continue
    }
  }
  if (val[0]==0x5354 && val[1]==0x4154 && (val[2]==0 || val[2]==0x4432)) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a MacDraw II template file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAWPRO, 0, MWAWDocument::MWAW_K_DRAW));
    return res;
  }
#ifdef DEBUG
  // we need the resource fork to find the colors, patterns, ... ; so not active in normal mode
  if (val[0]==0x6444 && val[1]==0x6f63 && val[2]==0x4432) { // dDocD2
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a MacDraw Pro file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAWPRO, 1, MWAWDocument::MWAW_K_DRAW));
    return res;
  }
  if (val[0]==0x644c && val[1]==0x6962 && val[2]==0x4432) { // dLibD2
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a MacDraw Pro template file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAWPRO, 1, MWAWDocument::MWAW_K_DRAW));
    return res;
  }
#endif
  if (val[0]==2 && val[1]==0 && val[2]==2 && val[3]==0x262 && val[4]==0x262) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a MacDraft file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAFT, 1, MWAWDocument::MWAW_K_DRAW));
    return res;
  }
  if (val[0]==0x4859 && val[1]==0x4c53 && val[2]==0x0210) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a HanMac Word-K file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_HANMACWORDK, 1));
    return res;
  }
  if (val[0]==0x594c && val[1]==0x5953 && val[2]==0x100) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a HanMac Word-J file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_HANMACWORDJ, 1));
    return res;
  }
  if (val[0]==0x6163 && val[1]==0x6633 && val[2]<9) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a FreeHand v1\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_FREEHAND, 1, MWAWDocument::MWAW_K_DRAW));
    return res;
  }
  if (val[0]==0x4648 && val[1]==0x4432 && val[2]<20) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a FreeHand v2\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_FREEHAND, 2, MWAWDocument::MWAW_K_DRAW));
    return res;
  }
  if (val[0]==3 && val[1]==0x4d52 && val[2]==0x4949 && val[3]==0x80) { // MRII
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MORE, 2));
    return res;
  }
  if (val[0]==6 && val[1]==0x4d4f && val[2]==0x5233 && val[3]==0x80) { // MOR3
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MORE, 3));
    return res;
  }
  if ((val[0]==0x100||val[0]==0x200) && val[2]==0x4558 && val[3]==0x5057) { // CHANGEME: ClarisDraw
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CLARISDRAW, 1, MWAWDocument::MWAW_K_DRAW));
    return res;
  }

  if (val[0]==0x100 || val[0]==0x200) {
    if (val[1]==0x5a57 && val[2]==0x5254) {
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_GREATWORKS, val[0]==0x100 ? 1 : 2));
      return res;
    }
    if (val[1]==0x5a4f && val[2]==0x424a) {
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_GREATWORKS, val[0]==0x100 ? 1 : 2, MWAWDocument::MWAW_K_DRAW));
      return res;
    }
    if (val[1]==0x5a43 && val[2]==0x414C) {
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_GREATWORKS, val[0]==0x100 ? 1 : 2, MWAWDocument::MWAW_K_SPREADSHEET));
      return res;
    }
    if (val[1]==0x5a44 && val[2]==0x4253) {
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_GREATWORKS, val[0]==0x100 ? 1 : 2, MWAWDocument::MWAW_K_DATABASE));
      return res;
    }
    // maybe we can also add outline: if (val[1]==0x5a4f && val[2]==0x4c4e)
  }
  if (val[0]==0x11ab && val[1]==0 && val[2]==0x13e8 && val[3]==0) {
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTMULTIPLAN, 1, MWAWDocument::MWAW_K_SPREADSHEET));
    return res;
  }
  if (val[3]==6 && val[4]<6) {
    if (val[0]==0x4d44 && val[1]==0x4443 && val[2]==0x3230) {
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAFT, 4, MWAWDocument::MWAW_K_DRAW));
      return res;
    }
    // can be a library file, this will be test in the parser
    if (input->size()>=30)
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAFT, 4, MWAWDocument::MWAW_K_DRAW));
  }
  // magic ole header
  if (val[0]==0xd0cf && val[1]==0x11e0 && val[2]==0xa1b1 && val[3]==0x1ae1 && input->isStructured()) {
    MWAWInputStreamPtr mainOle = input->getSubStreamByName("MN0");
    if (mainOle && mainOle->readULong(4) == 0x43484e4b)
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 4));
    else if (mainOle && mainOle->size()>18) {
      mainOle->seek(16, librevenge::RVNG_SEEK_SET);
      auto value=static_cast<int>(mainOle->readULong(2));
      switch (value) {
      case 2:
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 4, MWAWDocument::MWAW_K_DATABASE));
        break;
      case 3:
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 4, MWAWDocument::MWAW_K_SPREADSHEET));
        break;
      case 12:
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, 4, MWAWDocument::MWAW_K_DRAW));
        break;
      default:
        break;
      }
    }
    if (!mainOle && input->getSubStreamByName("PP40"))
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_POWERPOINT, 4, MWAWDocument::MWAW_K_PRESENTATION));
    else if (!mainOle && input->getSubStreamByName("PowerPoint Document") && input->getSubStreamByName("PersistentStorage Directory"))
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_POWERPOINT, 7, MWAWDocument::MWAW_K_PRESENTATION));
  }

  if ((val[0]==0xfe32 && val[1]==0) || (val[0]==0xfe34 && val[1]==0) ||
      (val[0] == 0xfe37 && (val[1] == 0x23 || val[1] == 0x1c))) {
    int vers = -1;
    switch (val[1]) {
    case 0:
      if (val[0]==0xfe34) {
        MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a Word 3.0 file\n"));
        vers = 3;
      }
      else if (val[0]==0xfe32) {
        MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a Word 1.0 file\n"));
        vers = 1;
      }
      break;
    case 0x1c:
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a Word 4.0 file\n"));
      vers = 4;
      break;
    case 0x23:
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a Word 5.0 file\n"));
      vers = 5;
      break;
    default:
      break;
    }
    if (vers >= 0)
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORD, vers));
  }
  if (val[0]==0xbad && val[1]==0xdeed && val[2]==0 && (val[3]>=2 && val[3]<=3)) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a Presentation file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_POWERPOINT, val[3], MWAWDocument::MWAW_K_PRESENTATION));
  }
  if (val[0]==0xedde && val[1]==0xad0b && val[3]==0 && (val[2]&0xFF)==0) {
    int vers=(val[2]>>8);
    if (vers>=2 && vers<=3) {
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a Presentation file\n"));
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_POWERPOINT, vers, MWAWDocument::MWAW_K_PRESENTATION));
    }
  }
  if (val[0]==0x4348 && val[1]==0x4e4b && val[2]==0x100 && val[3]==0) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a Style file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_STYLE, 1));
  }
  if (val[0]==0x0447 && val[1]==0x4d30 && val[2]==0x3400) { // ^DGM04
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a MouseWrite file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MOUSEWRITE, 1));
  }
  // ----------- less discriminant ------------------
  if (val[0] == 0x2e && val[1] == 0x2e) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a MacWrite II file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACWRITEPRO, 0));
  }
  if (val[0] == 4 && val[1] == 4) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a MacWritePro file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACWRITEPRO, 1));
  }
  if (val[0] == 0x7704) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a MindWrite file 2.1\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MINDWRITE, 2));
  }

  // ----------- other ------------------
  if (val[0]==0 && val[1]==0 && val[2]==0 && val[3]==0) {
    input->seek(8, librevenge::RVNG_SEEK_SET);
    auto value=static_cast<int>(input->readULong(1));
    if (value==0x4 || value==0x44) {
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a WriteNow 1.0 or 2.0 file\n"));
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_WRITENOW, 2));
    }
  }
  if (val[0]==0 && input->size() > 32) {
    input->seek(16, librevenge::RVNG_SEEK_SET);
    if (input->readLong(2)==0x688f && input->readLong(2)==0x688f) {
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a RagTime file\n"));
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_RAGTIME));
    }
  }
  if (val[0]==0) {
    int vers = -1;
    switch (val[1]) {
    case 4:
      vers = 1;
      break;
    case 8:
      vers = 2;
      break;
    case 9:
      vers = 3;
      break;
    case 11: // embedded data
      vers = 4;
      break;
    default:
      break;
    }
    if (vers > 0 && input->size()>16) {
      input->seek(16, librevenge::RVNG_SEEK_SET);
      auto value=static_cast<int>(input->readULong(2));
      switch (value) {
      case 1:
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, vers));
        break;
      case 2:
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, vers, MWAWDocument::MWAW_K_DATABASE));
        break;
      case 3:
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, vers, MWAWDocument::MWAW_K_SPREADSHEET));
        break;
      case 12:
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MICROSOFTWORKS, vers, MWAWDocument::MWAW_K_DRAW));
        break;
      default:
        break;
      }
    }
  }
  if (val[0]==0x4d44 && input->size()>=512) { // maybe a MacDraw 0 file, will be check later
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACDRAW, 0, MWAWDocument::MWAW_K_DRAW));
  }
  if (val[0] == 3 || val[0] == 6) {
    // version will be print by MacWrtParser::check
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACWRITE, val[0]));
  }
  if (val[0] == 0x110) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a Writerplus file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_WRITERPLUS, 1));
  }
  if (val[0] == 0x1000) {
    input->seek(10, librevenge::RVNG_SEEK_SET);
    auto value=static_cast<int>(input->readULong(2));
    // 1: bitmap, 2: vectorized graphic
    if (value==1)
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_SUPERPAINT, 1, MWAWDocument::MWAW_K_PAINT));
    else if (value==2)
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_SUPERPAINT, 1, MWAWDocument::MWAW_K_DRAW));
  }
  if (val[0]==0 && (val[1]==0x7FFF || val[1]==0x8000)) {
    MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a potential PixelPaint file\n"));
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_PIXELPAINT, (val[1]==0x7FFF) ? 1  : 2, MWAWDocument::MWAW_K_PAINT));
  }
  if (val[0]>=1 && val[0]<=4) {
    int sSz=(val[1]>>8);
    if (sSz>=6 && sSz<=8) {
      // check if we find a date
      input->seek(3, librevenge::RVNG_SEEK_SET);
      bool ok=true;
      int numSlash=0;
      for (int i=0; i<sSz; ++i) {
        auto c=char(input->readULong(1));
        if (c>='0' && c<='9')
          continue;
        if (c=='/')
          ++numSlash;
        else {
          ok=false;
          break;
        }
      }
      if (ok && numSlash==2)
        res.push_back(MWAWHeader(MWAWDocument::MWAW_T_CRICKETDRAW, 1, MWAWDocument::MWAW_K_DRAW));
    }
  }

  //
  // check for pict
  //
  for (int st=0; st<2; ++st) {
    if (!input->checkPosition(512*st+13))
      break;
    input->seek(512*st+10, librevenge::RVNG_SEEK_SET);
    auto value=static_cast<int>(input->readULong(2));
    if (value==0x1101) {
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_APPLEPICT, 1, MWAWDocument::MWAW_K_DRAW));
      break;
    }
    else if (value==0x11 && input->readULong(2)==0x2ff && input->readULong(2) == 0xC00) {
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_APPLEPICT, 2, MWAWDocument::MWAW_K_DRAW));
      break;
    }
  }
  //
  // middle of file
  //
  if (input->size()>=512+720*2) {
    // check for a MacPaint file
    input->seek(512, librevenge::RVNG_SEEK_SET);
    bool ok=true;
    // check the first 3 row
    for (int row=0; row<3; ++row) {
      int lastColor=-1;
      int col=0;
      while (col<72) {
        if (input->tell()+2>input->size()) {
          ok=false;
          break;
        }
        auto wh=static_cast<int>(input->readULong(1));
        if (wh>=0x81) {
          auto color=static_cast<int>(input->readULong(1));
          // consider that repeat color is anormal...
          if (col+(0x101-wh)>72 || (lastColor>=0 && color==lastColor)) {
            ok=false;
            break;
          }
          col+=(0x101-wh);
          lastColor=color;
          continue;
        }
        if (col+1+wh>72) {
          ok=false;
          break;
        }
        lastColor=-1;
        col += wh+1;
        input->seek(wh+1, librevenge::RVNG_SEEK_CUR);
      }
      if (!ok) break;
    }
    if (ok) {
      MWAW_DEBUG_MSG(("MWAWHeader::constructHeader: find a potential MacPaint file\n"));
      res.push_back(MWAWHeader(MWAWDocument::MWAW_T_MACPAINT, 1, MWAWDocument::MWAW_K_PAINT));
    }
  }
  //
  //ok now look at the end of file
  //
  if (input->seek(-4, librevenge::RVNG_SEEK_END))
    return res;
  int lVal[2];
  for (auto &v : lVal) v=int(input->readULong(2));
  if (lVal[0] == 0x4E4C && lVal[1]==0x544F) // NLTO
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_ACTA, 2));
  else if (lVal[1]==0 && val[0]==1 && (val[1]==1||val[1]==2))
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_ACTA, 1));
  else if (lVal[0] == 0x4657 && lVal[1]==0x5254) // FWRT
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_FULLWRITE, 2));
  else if (lVal[0] == 0 && lVal[1]==1) // not probable, but
    res.push_back(MWAWHeader(MWAWDocument::MWAW_T_FULLWRITE, 1));

  input->seek(0, librevenge::RVNG_SEEK_SET);
  return res;
}
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: