/* -*- 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.
*/

#include <iostream>

#include "libmwaw_internal.hxx"

#include "MWAWFontConverter.hxx"
#include "MWAWFontSJISConverter.hxx"


//! Internal namespace used to store the data used by MWAWFontConverterInternal
namespace MWAWFontConverterInternal
{
//! Internal and low level: tools to convert Macintosh characters
namespace Data
{
//! Internal and low level: a class to store a conversion map for character, ...
struct ConversionData {
  //! constructor
  ConversionData(std::map<unsigned char, unsigned long> &map,
                 char const *odtName="", int delta=0)
    : m_encoding(MWAWFontConverter::E_DEFAULT), m_conversion(map), m_name(odtName), m_deltaSize(delta) {}
  //! constructor for different encoding
  ConversionData(std::map<unsigned char, unsigned long> &map, MWAWFontConverter::Encoding encoding, char const *odtName="", int delta=0)
    : m_encoding(encoding), m_conversion(map), m_name(odtName), m_deltaSize(delta) {}

  //! the character encoding
  MWAWFontConverter::Encoding m_encoding;
  //! the conversion map character -> unicode
  std::map<unsigned char, unsigned long> &m_conversion;
  //! the odt font name (if empty used the name)
  std::string m_name;
  //! the size delta: odtSize = fSize + deltaSize
  int m_deltaSize;
};

// Courtesy of unicode.org: http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMAN.TXT
//! Internal and Low level: vector ( char, unicode) for roman font
static int const s_romanUnicode [] = {
  0x20,0x0020,  0x21,0x0021,  0x22,0x0022,  0x23,0x0023,  0x24,0x0024,
  0x25,0x0025,  0x26,0x0026,  0x27,0x0027,  0x28,0x0028,  0x29,0x0029,
  0x2A,0x002A,  0x2B,0x002B,  0x2C,0x002C,  0x2D,0x002D,  0x2E,0x002E,
  0x2F,0x002F,  0x30,0x0030,  0x31,0x0031,  0x32,0x0032,  0x33,0x0033,
  0x34,0x0034,  0x35,0x0035,  0x36,0x0036,  0x37,0x0037,  0x38,0x0038,
  0x39,0x0039,  0x3A,0x003A,  0x3B,0x003B,  0x3C,0x003C,  0x3D,0x003D,
  0x3E,0x003E,  0x3F,0x003F,  0x40,0x0040,  0x41,0x0041,  0x42,0x0042,
  0x43,0x0043,  0x44,0x0044,  0x45,0x0045,  0x46,0x0046,  0x47,0x0047,
  0x48,0x0048,  0x49,0x0049,  0x4A,0x004A,  0x4B,0x004B,  0x4C,0x004C,
  0x4D,0x004D,  0x4E,0x004E,  0x4F,0x004F,  0x50,0x0050,  0x51,0x0051,
  0x52,0x0052,  0x53,0x0053,  0x54,0x0054,  0x55,0x0055,  0x56,0x0056,
  0x57,0x0057,  0x58,0x0058,  0x59,0x0059,  0x5A,0x005A,  0x5B,0x005B,
// in icelandic : 5f='|o'
// in czech : 5f='s' (final 's' or begin word letter 'z')
  0x5C,0x005C,  0x5D,0x005D,  0x5E,0x005E,  0x5F,0x005F,  0x60,0x0060,
  0x61,0x0061,  0x62,0x0062,  0x63,0x0063,  0x64,0x0064,  0x65,0x0065,
  0x66,0x0066,  0x67,0x0067,  0x68,0x0068,  0x69,0x0069,  0x6A,0x006A,
  0x6B,0x006B,  0x6C,0x006C,  0x6D,0x006D,  0x6E,0x006E,  0x6F,0x006F,
  0x70,0x0070,  0x71,0x0071,  0x72,0x0072,  0x73,0x0073,  0x74,0x0074,
  0x75,0x0075,  0x76,0x0076,  0x77,0x0077,  0x78,0x0078,  0x79,0x0079,
  0x7A,0x007A,  0x7B,0x007B,  0x7C,0x007C,  0x7D,0x007D,  0x7E,0x007E,
  0x7F,0x007F,  0x80,0x00C4,  0x81,0x00C5,  0x82,0x00C7,  0x83,0x00C9,
  0x84,0x00D1,  0x85,0x00D6,  0x86,0x00DC,  0x87,0x00E1,  0x88,0x00E0,
  0x89,0x00E2,  0x8A,0x00E4,  0x8B,0x00E3,  0x8C,0x00E5,  0x8D,0x00E7,
  0x8E,0x00E9,  0x8F,0x00E8,  0x90,0x00EA,  0x91,0x00EB,  0x92,0x00ED,
  0x93,0x00EC,  0x94,0x00EE,  0x95,0x00EF,  0x96,0x00F1,  0x97,0x00F3,
  0x98,0x00F2,  0x99,0x00F4,  0x9A,0x00F6,  0x9B,0x00F5,  0x9C,0x00FA,
  0x9D,0x00F9,  0x9E,0x00FB,  0x9F,0x00FC,  0xA0,0x2020,  0xA1,0x00B0,
  0xA2,0x00A2,  0xA3,0x00A3,  0xA4,0x00A7,  0xA5,0x2022,  0xA6,0x00B6,
  0xA7,0x00DF,  0xA8,0x00AE,  0xA9,0x00A9,  0xAA,0x2122,  0xAB,0x00B4,
  0xAC,0x00A8,  0xAD,0x2260,  0xAE,0x00C6,  0xAF,0x00D8,  0xB0,0x221E,
  0xB1,0x00B1,  0xB2,0x2264,  0xB3,0x2265,  0xB4,0x00A5,  0xB5,0x00B5,
  0xB6,0x2202,  0xB7,0x2211,  0xB8,0x220F,  0xB9,0x03C0,  0xBA,0x222B,
  0xBB,0x00AA,  0xBC,0x00BA,  0xBD,0x03A9,  0xBE,0x00E6,  0xBF,0x00F8,
  0xC0,0x00BF,  0xC1,0x00A1,  0xC2,0x00AC,  0xC3,0x221A,  0xC4,0x0192,
  0xC5,0x2248,  0xC6,0x2206,  0xC7,0x00AB,  0xC8,0x00BB,  0xC9,0x2026,
  0xCA,0x00A0,  0xCB,0x00C0,  0xCC,0x00C3,  0xCD,0x00D5,  0xCE,0x0152,
  0xCF,0x0153,  0xD0,0x2013,  0xD1,0x2014,  0xD2,0x201C,  0xD3,0x201D,
  0xD4,0x2018,  0xD5,0x2019,  0xD6,0x00F7,  0xD7,0x25CA,  0xD8,0x00FF,
  0xD9,0x0178,  0xDA,0x2044,  0xDB,0x20AC,  0xDC,0x2039,  0xDD,0x203A,
  0xDE,0xFB01,  0xDF,0xFB02,  0xE0,0x2021,  0xE1,0x00B7,  0xE2,0x201A,
// E6 = non breaking space (instead of 0x00CA) ?
  0xE3,0x201E,  0xE4,0x2030,  0xE5,0x00C2,  0xE6,0x00CA,  0xE7,0x00C1,
  0xE8,0x00CB,  0xE9,0x00C8,  0xEA,0x00CD,  0xEB,0x00CE,  0xEC,0x00CF,
  0xED,0x00CC,  0xEE,0x00D3,  0xEF,0x00D4,  0xF0,0xF8FF,  0xF1,0x00D2,
  0xF2,0x00DA,  0xF3,0x00DB,  0xF4,0x00D9,  0xF5,0x0131,  0xF6,0x02C6,
  0xF7,0x02DC,  0xF8,0x00AF,  0xF9,0x02D8,  0xFA,0x02D9,  0xFB,0x02DA,
  0xFC,0x00B8,  0xFD,0x02DD,  0xFE,0x02DB,  0xFF,0x02C7
};

// Courtesy of unicode.org: http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/CENTEURO.TXT
//! Internal and Low level: vector (char, unicode) for Central european font
static int const s_centralEuroUnicode[] = {
  0x20,0x0020, 0x21,0x0021, 0x22,0x0022, 0x23,0x0023, 0x24,0x0024, 0x25,0x0025, 0x26,0x0026, 0x27,0x0027,
  0x28,0x0028, 0x29,0x0029, 0x2A,0x002A, 0x2B,0x002B, 0x2C,0x002C, 0x2D,0x002D, 0x2E,0x002E, 0x2F,0x002F,
  0x30,0x0030, 0x31,0x0031, 0x32,0x0032, 0x33,0x0033, 0x34,0x0034, 0x35,0x0035, 0x36,0x0036, 0x37,0x0037,
  0x38,0x0038, 0x39,0x0039, 0x3A,0x003A, 0x3B,0x003B, 0x3C,0x003C, 0x3D,0x003D, 0x3E,0x003E, 0x3F,0x003F,
  0x40,0x0040, 0x41,0x0041, 0x42,0x0042, 0x43,0x0043, 0x44,0x0044, 0x45,0x0045, 0x46,0x0046, 0x47,0x0047,
  0x48,0x0048, 0x49,0x0049, 0x4A,0x004A, 0x4B,0x004B, 0x4C,0x004C, 0x4D,0x004D, 0x4E,0x004E, 0x4F,0x004F,
  0x50,0x0050, 0x51,0x0051, 0x52,0x0052, 0x53,0x0053, 0x54,0x0054, 0x55,0x0055, 0x56,0x0056, 0x57,0x0057,
  0x58,0x0058, 0x59,0x0059, 0x5A,0x005A, 0x5B,0x005B, 0x5C,0x005C, 0x5D,0x005D, 0x5E,0x005E, 0x5F,0x005F,
  0x60,0x0060, 0x61,0x0061, 0x62,0x0062, 0x63,0x0063, 0x64,0x0064, 0x65,0x0065, 0x66,0x0066, 0x67,0x0067,
  0x68,0x0068, 0x69,0x0069, 0x6A,0x006A, 0x6B,0x006B, 0x6C,0x006C, 0x6D,0x006D, 0x6E,0x006E, 0x6F,0x006F,
  0x70,0x0070, 0x71,0x0071, 0x72,0x0072, 0x73,0x0073, 0x74,0x0074, 0x75,0x0075, 0x76,0x0076, 0x77,0x0077,
  0x78,0x0078, 0x79,0x0079, 0x7A,0x007A, 0x7B,0x007B, 0x7C,0x007C, 0x7D,0x007D, 0x7E,0x007E,
  0x80,0x00C4, 0x81,0x0100, 0x82,0x0101, 0x83,0x00C9, 0x84,0x0104, 0x85,0x00D6, 0x86,0x00DC, 0x87,0x00E1,
  0x88,0x0105, 0x89,0x010C, 0x8A,0x00E4, 0x8B,0x010D, 0x8C,0x0106, 0x8D,0x0107, 0x8E,0x00E9, 0x8F,0x0179,
  0x90,0x017A, 0x91,0x010E, 0x92,0x00ED, 0x93,0x010F, 0x94,0x0112, 0x95,0x0113, 0x96,0x0116, 0x97,0x00F3,
  0x98,0x0117, 0x99,0x00F4, 0x9A,0x00F6, 0x9B,0x00F5, 0x9C,0x00FA, 0x9D,0x011A, 0x9E,0x011B, 0x9F,0x00FC,
  0xA0,0x2020, 0xA1,0x00B0, 0xA2,0x0118, 0xA3,0x00A3, 0xA4,0x00A7, 0xA5,0x2022, 0xA6,0x00B6, 0xA7,0x00DF,
  0xA8,0x00AE, 0xA9,0x00A9, 0xAA,0x2122, 0xAB,0x0119, 0xAC,0x00A8, 0xAD,0x2260, 0xAE,0x0123, 0xAF,0x012E,
  0xB0,0x012F, 0xB1,0x012A, 0xB2,0x2264, 0xB3,0x2265, 0xB4,0x012B, 0xB5,0x0136, 0xB6,0x2202, 0xB7,0x2211,
  0xB8,0x0142, 0xB9,0x013B, 0xBA,0x013C, 0xBB,0x013D, 0xBC,0x013E, 0xBD,0x0139, 0xBE,0x013A, 0xBF,0x0145,
  0xC0,0x0146, 0xC1,0x0143, 0xC2,0x00AC, 0xC3,0x221A, 0xC4,0x0144, 0xC5,0x0147, 0xC6,0x2206, 0xC7,0x00AB,
  0xC8,0x00BB, 0xC9,0x2026, 0xCA,0x00A0, 0xCB,0x0148, 0xCC,0x0150, 0xCD,0x00D5, 0xCE,0x0151, 0xCF,0x014C,
  0xD0,0x2013, 0xD1,0x2014, 0xD2,0x201C, 0xD3,0x201D, 0xD4,0x2018, 0xD5,0x2019, 0xD6,0x00F7, 0xD7,0x25CA,
  0xD8,0x014D, 0xD9,0x0154, 0xDA,0x0155, 0xDB,0x0158, 0xDC,0x2039, 0xDD,0x203A, 0xDE,0x0159, 0xDF,0x0156,
  0xE0,0x0157, 0xE1,0x0160, 0xE2,0x201A, 0xE3,0x201E, 0xE4,0x0161, 0xE5,0x015A, 0xE6,0x015B, 0xE7,0x00C1,
  0xE8,0x0164, 0xE9,0x0165, 0xEA,0x00CD, 0xEB,0x017D, 0xEC,0x017E, 0xED,0x016A, 0xEE,0x00D3, 0xEF,0x00D4,
  0xF0,0x016B, 0xF1,0x016E, 0xF2,0x00DA, 0xF3,0x016F, 0xF4,0x0170, 0xF5,0x0171, 0xF6,0x0172, 0xF7,0x0173,
  0xF8,0x00DD, 0xF9,0x00FD, 0xFA,0x0137, 0xFB,0x017B, 0xFC,0x0141, 0xFD,0x017C, 0xFE,0x0122, 0xFF,0x02C7,
};

// Courtesy of unicode.org: http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/CYRILLIC.TXT
//! Internal and Low level: vector (char, unicode) for Cyrillic font
static int const s_cyrillicUnicode[] = {
  0x20,0x0020, 0x21,0x0021, 0x22,0x0022, 0x23,0x0023, 0x24,0x0024, 0x25,0x0025, 0x26,0x0026, 0x27,0x0027,
  0x28,0x0028, 0x29,0x0029, 0x2A,0x002A, 0x2B,0x002B, 0x2C,0x002C, 0x2D,0x002D, 0x2E,0x002E, 0x2F,0x002F,
  0x30,0x0030, 0x31,0x0031, 0x32,0x0032, 0x33,0x0033, 0x34,0x0034, 0x35,0x0035, 0x36,0x0036, 0x37,0x0037,
  0x38,0x0038, 0x39,0x0039, 0x3A,0x003A, 0x3B,0x003B, 0x3C,0x003C, 0x3D,0x003D, 0x3E,0x003E, 0x3F,0x003F,
  0x40,0x0040, 0x41,0x0041, 0x42,0x0042, 0x43,0x0043, 0x44,0x0044, 0x45,0x0045, 0x46,0x0046, 0x47,0x0047,
  0x48,0x0048, 0x49,0x0049, 0x4A,0x004A, 0x4B,0x004B, 0x4C,0x004C, 0x4D,0x004D, 0x4E,0x004E, 0x4F,0x004F,
  0x50,0x0050, 0x51,0x0051, 0x52,0x0052, 0x53,0x0053, 0x54,0x0054, 0x55,0x0055, 0x56,0x0056, 0x57,0x0057,
  0x58,0x0058, 0x59,0x0059, 0x5A,0x005A, 0x5B,0x005B, 0x5C,0x005C, 0x5D,0x005D, 0x5E,0x005E, 0x5F,0x005F,
  0x60,0x0060, 0x61,0x0061, 0x62,0x0062, 0x63,0x0063, 0x64,0x0064, 0x65,0x0065, 0x66,0x0066, 0x67,0x0067,
  0x68,0x0068, 0x69,0x0069, 0x6A,0x006A, 0x6B,0x006B, 0x6C,0x006C, 0x6D,0x006D, 0x6E,0x006E, 0x6F,0x006F,
  0x70,0x0070, 0x71,0x0071, 0x72,0x0072, 0x73,0x0073, 0x74,0x0074, 0x75,0x0075, 0x76,0x0076, 0x77,0x0077,
  0x78,0x0078, 0x79,0x0079, 0x7A,0x007A, 0x7B,0x007B, 0x7C,0x007C, 0x7D,0x007D, 0x7E,0x007E,
  0x80,0x0410, 0x81,0x0411, 0x82,0x0412, 0x83,0x0413, 0x84,0x0414, 0x85,0x0415, 0x86,0x0416, 0x87,0x0417,
  0x88,0x0418, 0x89,0x0419, 0x8A,0x041A, 0x8B,0x041B, 0x8C,0x041C, 0x8D,0x041D, 0x8E,0x041E, 0x8F,0x041F,
  0x90,0x0420, 0x91,0x0421, 0x92,0x0422, 0x93,0x0423, 0x94,0x0424, 0x95,0x0425, 0x96,0x0426, 0x97,0x0427,
  0x98,0x0428, 0x99,0x0429, 0x9A,0x042A, 0x9B,0x042B, 0x9C,0x042C, 0x9D,0x042D, 0x9E,0x042E, 0x9F,0x042F,
  0xA0,0x2020, 0xA1,0x00B0, 0xA2,0x0490, 0xA3,0x00A3, 0xA4,0x00A7, 0xA5,0x2022, 0xA6,0x00B6, 0xA7,0x0406,
  0xA8,0x00AE, 0xA9,0x00A9, 0xAA,0x2122, 0xAB,0x0402, 0xAC,0x0452, 0xAD,0x2260, 0xAE,0x0403, 0xAF,0x0453,
  0xB0,0x221E, 0xB1,0x00B1, 0xB2,0x2264, 0xB3,0x2265, 0xB4,0x0456, 0xB5,0x00B5, 0xB6,0x0491, 0xB7,0x0408,
  0xB8,0x0404, 0xB9,0x0454, 0xBA,0x0407, 0xBB,0x0457, 0xBC,0x0409, 0xBD,0x0459, 0xBE,0x040A, 0xBF,0x045A,
  0xC0,0x0458, 0xC1,0x0405, 0xC2,0x00AC, 0xC3,0x221A, 0xC4,0x0192, 0xC5,0x2248, 0xC6,0x2206, 0xC7,0x00AB,
  0xC8,0x00BB, 0xC9,0x2026, 0xCA,0x00A0, 0xCB,0x040B, 0xCC,0x045B, 0xCD,0x040C, 0xCE,0x045C, 0xCF,0x0455,
  0xD0,0x2013, 0xD1,0x2014, 0xD2,0x201C, 0xD3,0x201D, 0xD4,0x2018, 0xD5,0x2019, 0xD6,0x00F7, 0xD7,0x201E,
  0xD8,0x040E, 0xD9,0x045E, 0xDA,0x040F, 0xDB,0x045F, 0xDC,0x2116, 0xDD,0x0401, 0xDE,0x0451, 0xDF,0x044F,
  0xE0,0x0430, 0xE1,0x0431, 0xE2,0x0432, 0xE3,0x0433, 0xE4,0x0434, 0xE5,0x0435, 0xE6,0x0436, 0xE7,0x0437,
  0xE8,0x0438, 0xE9,0x0439, 0xEA,0x043A, 0xEB,0x043B, 0xEC,0x043C, 0xED,0x043D, 0xEE,0x043E, 0xEF,0x043F,
  0xF0,0x0440, 0xF1,0x0441, 0xF2,0x0442, 0xF3,0x0443, 0xF4,0x0444, 0xF5,0x0445, 0xF6,0x0446, 0xF7,0x0447,
  0xF8,0x0448, 0xF9,0x0449, 0xFA,0x044A, 0xFB,0x044B, 0xFC,0x044C, 0xFD,0x044D, 0xFE,0x044E, 0xFF,0x20AC,
};

// Courtesy of unicode.org: http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/TURKISH.TXT
//! Internal and Low level: vector (char, unicode) for Turkish font ( diff to mac roman)
static int const s_turkishUnicode[] = {
  0xda,0x11e, 0xdb,0x11f, 0xdc,0x130, 0xdd,0x131, 0xde,0x15e, 0xdf,0x15f, 0xf5,0xf8a0
};

// Courtesy of unicode.org: http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/SYMBOL.TXT
//! Internal and Low level: vector (char, unicode) for symbol font
static int const s_symbolUnicode[] = {
  0x20,0x0020,  0x21,0x0021,  0x22,0x2200,  0x23,0x0023,  0x24,0x2203,
  0x25,0x0025,  0x26,0x0026,  0x27,0x220D,  0x28,0x0028,  0x29,0x0029,
  0x2A,0x2217,  0x2B,0x002B,  0x2C,0x002C,  0x2D,0x2212,  0x2E,0x002E,
  0x2F,0x002F,  0x30,0x0030,  0x31,0x0031,  0x32,0x0032,  0x33,0x0033,
  0x34,0x0034,  0x35,0x0035,  0x36,0x0036,  0x37,0x0037,  0x38,0x0038,
  0x39,0x0039,  0x3A,0x003A,  0x3B,0x003B,  0x3C,0x003C,  0x3D,0x003D,
  0x3E,0x003E,  0x3F,0x003F,  0x40,0x2245,  0x41,0x0391,  0x42,0x0392,
  0x43,0x03A7,  0x44,0x0394,  0x45,0x0395,  0x46,0x03A6,  0x47,0x0393,
  0x48,0x0397,  0x49,0x0399,  0x4A,0x03D1,  0x4B,0x039A,  0x4C,0x039B,
  0x4D,0x039C,  0x4E,0x039D,  0x4F,0x039F,  0x50,0x03A0,  0x51,0x0398,
  0x52,0x03A1,  0x53,0x03A3,  0x54,0x03A4,  0x55,0x03A5,  0x56,0x03C2,
  0x57,0x03A9,  0x58,0x039E,  0x59,0x03A8,  0x5A,0x0396,  0x5B,0x005B,
  0x5C,0x2234,  0x5D,0x005D,  0x5E,0x22A5,  0x5F,0x005F,  0x60,0xF8E5,
  0x61,0x03B1,  0x62,0x03B2,  0x63,0x03C7,  0x64,0x03B4,  0x65,0x03B5,
  0x66,0x03C6,  0x67,0x03B3,  0x68,0x03B7,  0x69,0x03B9,  0x6A,0x03D5,
  0x6B,0x03BA,  0x6C,0x03BB,  0x6D,0x03BC,  0x6E,0x03BD,  0x6F,0x03BF,
  0x70,0x03C0,  0x71,0x03B8,  0x72,0x03C1,  0x73,0x03C3,  0x74,0x03C4,
  0x75,0x03C5,  0x76,0x03D6,  0x77,0x03C9,  0x78,0x03BE,  0x79,0x03C8,
  0x7A,0x03B6,  0x7B,0x007B,  0x7C,0x007C,  0x7D,0x007D,  0x7E,0x223C,
  0xA0,0x20AC,  0xA1,0x03D2,  0xA2,0x2032,  0xA3,0x2264,  0xA4,0x2044,
  0xA5,0x221E,  0xA6,0x0192,  0xA7,0x2663,  0xA8,0x2666,  0xA9,0x2665,
  0xAA,0x2660,  0xAB,0x2194,  0xAC,0x2190,  0xAD,0x2191,  0xAE,0x2192,
  0xAF,0x2193,  0xB0,0x00B0,  0xB1,0x00B1,  0xB2,0x2033,  0xB3,0x2265,
  0xB4,0x00D7,  0xB5,0x221D,  0xB6,0x2202,  0xB7,0x2022,  0xB8,0x00F7,
  0xB9,0x2260,  0xBA,0x2261,  0xBB,0x2248,  0xBC,0x2026,  0xBD,0x23D0,
  0xBE,0x23AF,  0xBF,0x21B5,  0xC0,0x2135,  0xC1,0x2111,  0xC2,0x211C,
  0xC3,0x2118,  0xC4,0x2297,  0xC5,0x2295,  0xC6,0x2205,  0xC7,0x2229,
  0xC8,0x222A,  0xC9,0x2283,  0xCA,0x2287,  0xCB,0x2284,  0xCC,0x2282,
  0xCD,0x2286,  0xCE,0x2208,  0xCF,0x2209,  0xD0,0x2220,  0xD1,0x2207,
  0xD2,0x00AE,  0xD3,0x00A9,  0xD4,0x2122,  0xD5,0x220F,  0xD6,0x221A,
  0xD7,0x22C5,  0xD8,0x00AC,  0xD9,0x2227,  0xDA,0x2228,  0xDB,0x21D4,
  0xDC,0x21D0,  0xDD,0x21D1,  0xDE,0x21D2,  0xDF,0x21D3,  0xE0,0x25CA,
  0xE1,0x3008,  0xE2,0x00AE,  0xE3,0x00A9,  0xE4,0x2122,  0xE5,0x2211,
  0xE6,0x239B,  0xE7,0x239C,  0xE8,0x239D,  0xE9,0x23A1,  0xEA,0x23A2,
  0xEB,0x23A3,  0xEC,0x23A7,  0xED,0x23A8,  0xEE,0x23A9,  0xEF,0x23AA,
  0xF0,0xF8FF,  0xF1,0x3009,  0xF2,0x222B,  0xF3,0x2320,  0xF4,0x23AE,
  0xF5,0x2321,  0xF6,0x239E,  0xF7,0x239F,  0xF8,0x23A0,  0xF9,0x23A4,
  0xFA,0x23A5,  0xFB,0x23A6,  0xFC,0x23AB,  0xFD,0x23AC,  0xFE,0x23AD
};

// Courtesy of unicode.org: http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/DINGBATS.TXT
//! Internal and Low level: vector (char, unicode) for dingbats font
static int const s_dingbatsUnicode[] = {
  0x20,0x0020,  0x21,0x2701,  0x22,0x2702,  0x23,0x2703,  0x24,0x2704,
  0x25,0x260E,  0x26,0x2706,  0x27,0x2707,  0x28,0x2708,  0x29,0x2709,
  0x2A,0x261B,  0x2B,0x261E,  0x2C,0x270C,  0x2D,0x270D,  0x2E,0x270E,
  0x2F,0x270F,  0x30,0x2710,  0x31,0x2711,  0x32,0x2712,  0x33,0x2713,
  0x34,0x2714,  0x35,0x2715,  0x36,0x2716,  0x37,0x2717,  0x38,0x2718,
  0x39,0x2719,  0x3A,0x271A,  0x3B,0x271B,  0x3C,0x271C,  0x3D,0x271D,
  0x3E,0x271E,  0x3F,0x271F,  0x40,0x2720,  0x41,0x2721,  0x42,0x2722,
  0x43,0x2723,  0x44,0x2724,  0x45,0x2725,  0x46,0x2726,  0x47,0x2727,
  0x48,0x2605,  0x49,0x2729,  0x4A,0x272A,  0x4B,0x272B,  0x4C,0x272C,
  0x4D,0x272D,  0x4E,0x272E,  0x4F,0x272F,  0x50,0x2730,  0x51,0x2731,
  0x52,0x2732,  0x53,0x2733,  0x54,0x2734,  0x55,0x2735,  0x56,0x2736,
  0x57,0x2737,  0x58,0x2738,  0x59,0x2739,  0x5A,0x273A,  0x5B,0x273B,
  0x5C,0x273C,  0x5D,0x273D,  0x5E,0x273E,  0x5F,0x273F,  0x60,0x2740,
  0x61,0x2741,  0x62,0x2742,  0x63,0x2743,  0x64,0x2744,  0x65,0x2745,
  0x66,0x2746,  0x67,0x2747,  0x68,0x2748,  0x69,0x2749,  0x6A,0x274A,
  0x6B,0x274B,  0x6C,0x25CF,  0x6D,0x274D,  0x6E,0x25A0,  0x6F,0x274F,
  0x70,0x2750,  0x71,0x2751,  0x72,0x2752,  0x73,0x25B2,  0x74,0x25BC,
  0x75,0x25C6,  0x76,0x2756,  0x77,0x25D7,  0x78,0x2758,  0x79,0x2759,
  0x7A,0x275A,  0x7B,0x275B,  0x7C,0x275C,  0x7D,0x275D,  0x7E,0x275E,
  0x80,0x2768,  0x81,0x2769,  0x82,0x276A,  0x83,0x276B,  0x84,0x276C,
  0x85,0x276D,  0x86,0x276E,  0x87,0x276F,  0x88,0x2770,  0x89,0x2771,
  0x8A,0x2772,  0x8B,0x2773,  0x8C,0x2774,  0x8D,0x2775,  0xA1,0x2761,
  0xA2,0x2762,  0xA3,0x2763,  0xA4,0x2764,  0xA5,0x2765,  0xA6,0x2766,
  0xA7,0x2767,  0xA8,0x2663,  0xA9,0x2666,  0xAA,0x2665,  0xAB,0x2660,
  0xAC,0x2460,  0xAD,0x2461,  0xAE,0x2462,  0xAF,0x2463,  0xB0,0x2464,
  0xB1,0x2465,  0xB2,0x2466,  0xB3,0x2467,  0xB4,0x2468,  0xB5,0x2469,
  0xB6,0x2776,  0xB7,0x2777,  0xB8,0x2778,  0xB9,0x2779,  0xBA,0x277A,
  0xBB,0x277B,  0xBC,0x277C,  0xBD,0x277D,  0xBE,0x277E,  0xBF,0x277F,
  0xC0,0x2780,  0xC1,0x2781,  0xC2,0x2782,  0xC3,0x2783,  0xC4,0x2784,
  0xC5,0x2785,  0xC6,0x2786,  0xC7,0x2787,  0xC8,0x2788,  0xC9,0x2789,
  0xCA,0x278A,  0xCB,0x278B,  0xCC,0x278C,  0xCD,0x278D,  0xCE,0x278E,
  0xCF,0x278F,  0xD0,0x2790,  0xD1,0x2791,  0xD2,0x2792,  0xD3,0x2793,
  0xD4,0x2794,  0xD5,0x2192,  0xD6,0x2194,  0xD7,0x2195,  0xD8,0x2798,
  0xD9,0x2799,  0xDA,0x279A,  0xDB,0x279B,  0xDC,0x279C,  0xDD,0x279D,
  0xDE,0x279E,  0xDF,0x279F,  0xE0,0x27A0,  0xE1,0x27A1,  0xE2,0x27A2,
  0xE3,0x27A3,  0xE4,0x27A4,  0xE5,0x27A5,  0xE6,0x27A6,  0xE7,0x27A7,
  0xE8,0x27A8,  0xE9,0x27A9,  0xEA,0x27AA,  0xEB,0x27AB,  0xEC,0x27AC,
  0xED,0x27AD,  0xEE,0x27AE,  0xEF,0x27AF,  0xF1,0x27B1,  0xF2,0x27B2,
  0xF3,0x27B3,  0xF4,0x27B4,  0xF5,0x27B5,  0xF6,0x27B6,  0xF7,0x27B7,
  0xF8,0x27B8,  0xF9,0x27B9,  0xFA,0x27BA,  0xFB,0x27BB,  0xFC,0x27BC,
  0xFD,0x27BD,  0xFE,0x27BE
};

// Courtesy of unicode.org: http://www.alanwood.net/demos/wingdings.html
//! Internal and Low level: vector (char, unicode) for wingdings font
static int const s_wingdingsUnicode[] = {
  0x20,0x0020,  0x21,0x270f,  0x22,0x2702,  0x23,0x2701,  0x24,0x1F453,
  0x25,0x1F514, 0x26,0x1F514, 0x27,0x2710/*candle*/, 0x28,0x260E, 0x29,0x2706,
  0x2A,0x2709,  0x2B,0x260E,  0x2C,0x1f4ea, 0x2D,0x1f4eb, 0x2E,0x1f4ec,
  0x2F,0x1f4ed, 0x30,0x1f4c1, 0x31,0x1f4c2, 0x32,0x1f4c4, 0x33,0x1f4c4,
  0x34,0x1f4c4, 0x35,0x25AF,  0x36,0x231B,  0x37,0x2328,  0x38,0x1F42F/*mouse*/,
  0x39,0x2328/*trackpad*/, 0x3A,0x1F4BB, 0x3B,0x2328/*harddisk*/, 0x3C,0x1F4BE,  0x3D,0x1F4BE,
  0x3E,0x2707,  0x3F,0x270D,  0x40,0x270D,  0x41,0x270c,  0x42,0x1F44C,
  0x43,0x1F44D, 0x44,0x1F44E, 0x45,0x261C,  0x46,0x261E,  0x47,0x261D,
  0x48,0x261F,  0x49,0x270B,  0x4A,0x263A,  0x4B,0x1F610, 0x4C,0x2639,
  0x4D,0x1F4A3, 0x4E,0x2620,  0x4F,0x2690,  0x50,0x1F6A9, 0x51,0x2708,
  0x52,0x263C,  0x53,0x1F4A7, 0x54,0x2744,  0x55,0x271E,  0x56,0x271E,
  0x57,0x271D,  0x58,0x2720,  0x59,0x2721,  0x5A,0x262a,  0x5B,0x262f,
  0x5C,0x0950,  0x5D,0x2638,  0x5E,0x2648,  0x5F,0x2649,  0x60,0x264a,
  0x61,0x264b,  0x62,0x264c,  0x63,0x264d,  0x64,0x264e,  0x65,0x264f,
  0x66,0x2650,  0x67,0x2651,  0x68,0x2652,  0x69,0x2653,  0x6A,0x0026,
  0x6B,0x0026,  0x6C,0x25CF,  0x6D,0x274D,  0x6E,0x25A0,  0x6F,0x27A1,
  0x70,0x2751,  0x71,0x2751,  0x72,0x2752,  0x73,0x2B27,  0x74,0x29EB,
  0x75,0x25C6,  0x76,0x2756,  0x77,0x2B25,  0x78,0x2327,  0x79,0x2353,
  0x7A,0x2318,  0x7B,0x2740,  0x7C,0x273F,  0x7D,0x275D,  0x7E,0x275E,
  0x7F,0x25AF,  0x80,0x24EA,  0x81,0x2460,  0x82,0x2461,  0x83,0x2462,
  0x84,0x2463,  0x85,0x2464,  0x86,0x2465,  0x87,0x2466,  0x88,0x2467,
  0x89,0x2468,  0x8A,0x2469,  0x8B,0x24FF,  0x8C,0x2776,  0x8D,0x2777,
  0x8E,0x2778,  0x8F,0x2779,  0x90,0x277A,  0x91,0x277B,  0x92,0x277C,
  0x93,0x277D,  0x94,0x277E,  0x95,0x277F,
  0x96,0x269B,  0x97,0x269B,  0x98,0x269B,  0x99,0x269B,
  0x9a,0x269B,  0x9b,0x269B,  0x9c,0x269B,  0x9d,0x269B,  // bud and vine leaf
  0x9E,0x00B7,  0x9F,0x277F,  0xA0,0x25AA,  0xA1,0x25CB,  0xA2,0x2B55,
  0xA3,0x2B55,  0xA4,0x25C9,  0xA5,0x25CE,  0xA6,0x25CB,
  0xA7,0x25AA,  0xA8,0x25FB,  0xA9,0x2726,  0xAA,0x2726,  0xAB,0x2605,
  0xAC,0x2736,  0xAD,0x2734,  0xAE,0x2739,  0xAF,0x2735,  0xB0,0x2316,
  0xB1,0x2316,  0xB2,0x27E1,  0xB3,0x2311,  0xB4,0x27E1,  0xB5,0x25CB,/*clock*/
  0xB6,0x2730,  0xB7,0x1F550, 0xB8,0x1F551, 0xB9,0x1F552, 0xBA,0x1F553,
  0xBB,0x1F554, 0xBC,0x1F555, 0xBD,0x1F556, 0xBE,0x1F557, 0xBF,0x1F558,
  0xC0,0x1F559, 0xC1,0x1F55A, 0xC2,0x1F55B, 0xC3,0x21B5,  0xC4,0x21B3,
  0xC5,0x21B0,  0xC6,0x21B1,  0xC7,0x21BB,  0xC8,0x21BA,  0xC9,0x21BA,
  0xCA,0x21BB,  0xCB,0x2722,  0xCC,0x2722,
  0xCD,0x2743,  0xCE,0x2743,  0xCF,0x2743,  0xD0,0x2743,
  0xD1,0x2743,  0xD2,0x2743,  0xD3,0x2743,  0xD4,0x2743,  /* normally leaf...*/
  0xD5,0x232B,  0xD6,0x2326,  0xD7,0x21E6,  0xD8,0x27A2,
  0xD9,0x21E7,  0xDA,0x21E9,  0xDB,0x21E6,  0xDC,0x27B2,  0xDD,0x21E7,
  0xDE,0x21E9,  0xDF,0x21E6,  0xE0,0x21E8,  0xE1,0x21E7,  0xE2,0x21E9,
  0xE3,0x2B00,  0xE4,0x2B01,  0xE5,0x2B03,  0xE6,0x2B02,  0xE7,0x21E6,
  0xE8,0x2794,  0xE9,0x21E7,  0xEA,0x21E9,  0xEB,0x2B00,  0xEC,0x2B01,
  0xED,0x2B03,  0xEE,0x2B02,  0xEF,0x21E6,  0xF0,0x27E8,  0xF1,0x27E7,
  0xF2,0x21E9,
  0xF3,0x2B04,  0xF4,0x21F3,  0xF5,0x2B00,  0xF6,0x2B01,  0xF7,0x2B03,
  0xF8,0x2B02,  0xF9,0x25AD,  0xFA,0x25AB,  0xFB,0x2717,  0xFC,0x2713,
  0xFD,0x2612,  0xFE,0x2611
};

//
// For the next one, we stored only the "known" differences between roman and font
//
/** Internal and Low level: vector (char, unicode) for cursive font

\note only characters which differs from roman*/
static int const s_cursiveIncompleteUnicode[] = {
  0xa2,0xBC, 0xa3,0x2153, 0xa4,0x2159, 0xaa,0xBD, 0xc1,0x2154
  // 0x40, 0xB0: some number,
};

/** Internal and Low level: vector (char, unicode) for math font

\note only characters which differs from roman */
static int const s_mathIncompleteUnicode[] = {
  0x22,0x222A, 0x27,0x222A,  0x28,0x2229, 0x2b,0x2260, 0x31,0x2282,
  0x33,0x2227, 0x36,0x2A2F,  0x39,0x2282, 0x43,0x2102, 0x44,0x216E,
  0x47,0x0393, 0x49,0x2160,  0x4e,0x2115, 0x52,0x211D, 0x5a,0x2124,
  0x63,0x0255, 0x64,0x03B4,  0x65,0x212F, 0x68,0x210E, 0x70,0x01BF,
  0x76,0x2174
};

/** Internal and Low level: vector (char, unicode) for scientific font

\note only characters which differs from roman*/
static int const s_scientificIncompleteUnicode[] = {
  0x23,0x0394, 0x40,0x221A,  0x49,0x2160, 0x56,0x2164, 0x5c,0x007C,
  0x5b,0x2192, 0x5d,0x2192,  0x90,0x211D, 0x91,0x2192, 0xa7,0x03C3,
  0xa9,0x03B3, 0xab,0x03F5,  0xad,0x2260, 0xc3,0x03C8, 0xcf,0x03B8,
  0xd1,0x223C, 0xd4,0x2192,  0xe3,0x2009, 0xe8,0x00a0, 0xec,0x2303,
  0xee,0x2227, 0xef,0x0305,  0xf2,0x2192
};

// other fonts with unknown names :
/** Internal and Low level: vector (char, unicode) for font 107

\note only characters which differs from roman */
static int const s_unknown107IncompleteUnicode[] = {
  0x76,0x221a
};
/** Internal and Low level: vector (char, unicode) for font 128

\note only characters which differs from roman*/
static int const s_unknown128IncompleteUnicode[] = {
  0x43,0x2102, 0x4e,0x2115, 0x52,0x211D, 0x61,0xFE3F, 0x76,0x2192
};
/** Internal and Low level: vector (char, unicode) for font 200

\note only characters which differs from roman */
static int const s_unknown200IncompleteUnicode[] = {
  0x76,0x2192, 0x77,0x2192, 0x61,0xFE3F
};

//! Internal and Low level: vector (char, unicode) for SJIS font (see MWAWFontSJISConverter )
static int const s_SJISSimplifiedUnicode[]= {
  0x20,0x0020, 0x21,0x0021, 0x22,0x0022, 0x23,0x0023, 0x24,0x0024, 0x25,0x0025, 0x26,0x0026, 0x27,0x0027,
  0x28,0x0028, 0x29,0x0029, 0x2A,0x002A, 0x2B,0x002B, 0x2C,0x002C, 0x2D,0x002D, 0x2E,0x002E, 0x2F,0x002F,
  0x30,0x0030, 0x31,0x0031, 0x32,0x0032, 0x33,0x0033, 0x34,0x0034, 0x35,0x0035, 0x36,0x0036, 0x37,0x0037,
  0x38,0x0038, 0x39,0x0039, 0x3A,0x003A, 0x3B,0x003B, 0x3C,0x003C, 0x3D,0x003D, 0x3E,0x003E, 0x3F,0x003F,
  0x40,0x0040, 0x41,0x0041, 0x42,0x0042, 0x43,0x0043, 0x44,0x0044, 0x45,0x0045, 0x46,0x0046, 0x47,0x0047,
  0x48,0x0048, 0x49,0x0049, 0x4A,0x004A, 0x4B,0x004B, 0x4C,0x004C, 0x4D,0x004D, 0x4E,0x004E, 0x4F,0x004F,
  0x50,0x0050, 0x51,0x0051, 0x52,0x0052, 0x53,0x0053, 0x54,0x0054, 0x55,0x0055, 0x56,0x0056, 0x57,0x0057,
  0x58,0x0058, 0x59,0x0059, 0x5A,0x005A, 0x5B,0x005B, 0x5C,0x00A5, 0x5D,0x005D, 0x5E,0x005E, 0x5F,0x005F,
  0x60,0x0060, 0x61,0x0061, 0x62,0x0062, 0x63,0x0063, 0x64,0x0064, 0x65,0x0065, 0x66,0x0066, 0x67,0x0067,
  0x68,0x0068, 0x69,0x0069, 0x6A,0x006A, 0x6B,0x006B, 0x6C,0x006C, 0x6D,0x006D, 0x6E,0x006E, 0x6F,0x006F,
  0x70,0x0070, 0x71,0x0071, 0x72,0x0072, 0x73,0x0073, 0x74,0x0074, 0x75,0x0075, 0x76,0x0076, 0x77,0x0077,
  0x78,0x0078, 0x79,0x0079, 0x7A,0x007A, 0x7B,0x007B, 0x7C,0x007C, 0x7D,0x007D, 0x7E,0x203E, 0x7F,0x007F,
  0xA1,0xFF61, 0xA2,0xFF62, 0xA3,0xFF63, 0xA4,0xFF64, 0xA5,0xFF65, 0xA6,0xFF66, 0xA7,0xFF67, 0xA8,0xFF68,
  0xA9,0xFF69, 0xAA,0xFF6A, 0xAB,0xFF6B, 0xAC,0xFF6C, 0xAD,0xFF6D, 0xAE,0xFF6E, 0xAF,0xFF6F, 0xB0,0xFF70,
  0xB1,0xFF71, 0xB2,0xFF72, 0xB3,0xFF73, 0xB4,0xFF74, 0xB5,0xFF75, 0xB6,0xFF76, 0xB7,0xFF77, 0xB8,0xFF78,
  0xB9,0xFF79, 0xBA,0xFF7A, 0xBB,0xFF7B, 0xBC,0xFF7C, 0xBD,0xFF7D, 0xBE,0xFF7E, 0xBF,0xFF7F, 0xC0,0xFF80,
  0xC1,0xFF81, 0xC2,0xFF82, 0xC3,0xFF83, 0xC4,0xFF84, 0xC5,0xFF85, 0xC6,0xFF86, 0xC7,0xFF87, 0xC8,0xFF88,
  0xC9,0xFF89, 0xCA,0xFF8A, 0xCB,0xFF8B, 0xCC,0xFF8C, 0xCD,0xFF8D, 0xCE,0xFF8E, 0xCF,0xFF8F, 0xD0,0xFF90,
  0xD1,0xFF91, 0xD2,0xFF92, 0xD3,0xFF93, 0xD4,0xFF94, 0xD5,0xFF95, 0xD6,0xFF96, 0xD7,0xFF97, 0xD8,0xFF98,
  0xD9,0xFF99, 0xDA,0xFF9A, 0xDB,0xFF9B, 0xDC,0xFF9C, 0xDD,0xFF9D, 0xDE,0xFF9E, 0xDF,0xFF9F
};

class KnownConversion
{
public:
  //! constructor
  KnownConversion() : m_convertMap(), m_familyMap(),
    m_romanMap(), m_centralEuroMap(), m_cyrillicMap(), m_turkishMap(), m_symbolMap(), m_dingbatsMap(), m_cursiveMap(),
    m_mathMap(), m_scientificMap(), m_wingdingsMap(), m_SJISMap(), m_unknown107Map(), m_unknown128Map(),
    m_unknown200Map(),
    m_defaultConv(m_romanMap),  m_centralEuroConv(m_centralEuroMap), m_cyrillicConv(m_cyrillicMap), m_turkishConv(m_turkishMap),
    m_timeConv(m_romanMap,"Times New Roman"),
    m_zapfChanceryConv(m_romanMap,"Apple Chancery", -2), m_symbolConv(m_symbolMap),
    m_dingbatsConv(m_dingbatsMap), m_cursiveConv(m_cursiveMap,"Apple Chancery"),
    m_mathConv(m_mathMap), m_scientificConv(m_scientificMap), m_wingdingsConv(m_wingdingsMap),
    m_SJISConv(m_SJISMap, MWAWFontConverter::E_SJIS),
    m_unknown107Conv(m_unknown107Map), m_unknown128Conv(m_unknown128Map),
    m_unknown200Conv(m_unknown200Map)
  {
    initMaps();
  }
  //! returns the conversion map which corresponds to a name, or the default map
  Data::ConversionData const &getConversionMaps(std::string fName);

  //! set a family correspondance
  void setFamily(std::string const &fName, std::string const &family)
  {
    if (fName.length() && family.length())
      m_familyMap[fName]=family;
  }
  //! return the default converter
  ConversionData const &getDefault() const
  {
    return m_defaultConv;
  }
protected:
  //! Internal and Low level: initializes all the conversion maps
  void initMaps();

  //! Internal and Low level: initializes a map with a vector of \a numElt elements (char, unicode)
  static void initAMap(int const *arr, size_t numElt, std::map<unsigned char, unsigned long> &map)
  {
    for (size_t i = 0; i < numElt; i++) {
      unsigned char c = static_cast<unsigned char>(arr[2*i]);
      unsigned long unicode = static_cast<unsigned long>(arr[2*i+1]);
      map[c] = unicode;
    }
  }

  /** the conversiont map fName -> ConversionData */
  std::map<std::string, ConversionData const *> m_convertMap;

  //! Internal and Low level: map font name -> family font name
  std::map<std::string, std::string> m_familyMap;

  //! Internal and Low level: map char -> unicode for roman font
  std::map<unsigned char, unsigned long> m_romanMap;
  //! Internal and Low level: map char -> unicode for central european font
  std::map<unsigned char, unsigned long> m_centralEuroMap;
  //! Internal and Low level: map char -> unicode for cyrillic font
  std::map<unsigned char, unsigned long> m_cyrillicMap;
  //! Internal and Low level: map char -> unicode for turkish font
  std::map<unsigned char, unsigned long> m_turkishMap;

  //! Internal and Low level: map char -> unicode for symbol font
  std::map<unsigned char, unsigned long> m_symbolMap;
  //! Internal and Low level: map char -> unicode for dingbats font
  std::map<unsigned char, unsigned long> m_dingbatsMap;
  //! Internal and Low level: map char -> unicode for cursive font
  std::map<unsigned char, unsigned long> m_cursiveMap;
  //! Internal and Low level: map char -> unicode for math font
  std::map<unsigned char, unsigned long> m_mathMap;
  //! Internal and Low level: map char -> unicode for scientific font
  std::map<unsigned char, unsigned long> m_scientificMap;
  //! Internal and Low level: map char -> unicode for wingdings font
  std::map<unsigned char, unsigned long> m_wingdingsMap;
  //! Internal and Low level: simplified map char -> unicode for SJIS font
  std::map<unsigned char, unsigned long> m_SJISMap;
  //! Internal and Low level: map char -> unicode for font 107
  std::map<unsigned char, unsigned long> m_unknown107Map;
  //! Internal and Low level: map char -> unicode for font 128
  std::map<unsigned char, unsigned long> m_unknown128Map;
  //! Internal and Low level: map char -> unicode for font 200
  std::map<unsigned char, unsigned long> m_unknown200Map;

  //! Internal and Low level: the default converter: roman
  ConversionData m_defaultConv;
  //! Internal and Low level: the default converter: central european
  ConversionData m_centralEuroConv;
  //! Internal and Low level: the default converter: cyrillic
  ConversionData m_cyrillicConv;
  //! Internal and Low level: the default converter: turkish
  ConversionData m_turkishConv;

  //! Internal and Low level: the converter for times font
  ConversionData m_timeConv;
  //! Internal and Low level: the converter for zapfChancery font
  ConversionData m_zapfChanceryConv;
  //! Internal and Low level: the converter for symbol font
  ConversionData m_symbolConv;
  //! Internal and Low level: the converter for dingbats font
  ConversionData m_dingbatsConv;
  //! Internal and Low level: the converter for cursive font
  ConversionData m_cursiveConv;
  //! Internal and Low level: the converter for math font
  ConversionData m_mathConv;
  //! Internal and Low level: the converter for scientific font
  ConversionData m_scientificConv;
  //! Internal and Low level: the converter for wingdings font
  ConversionData m_wingdingsConv;
  //! Internal and Low level: the converter for SJIS font
  ConversionData m_SJISConv;
  //! Internal and Low level: the converter for font 107
  ConversionData m_unknown107Conv;
  //! Internal and Low level: the converter for font 128
  ConversionData m_unknown128Conv;
  //! Internal and Low level: the converter for font 200
  ConversionData m_unknown200Conv;
};


//! Internal and Low level: initializes all the conversion maps
void KnownConversion::initMaps()
{
  size_t numRoman = sizeof(s_romanUnicode)/(2*sizeof(int));
  for (size_t i = 0; i < numRoman; i++) {
    unsigned char c = static_cast<unsigned char>(s_romanUnicode[2*i]);
    unsigned long unicode = static_cast<unsigned long>(s_romanUnicode[2*i+1]);
    m_romanMap[c] = m_turkishMap[c] = unicode;
    m_cursiveMap[c] = m_mathMap[c] = m_scientificMap[c] = unicode;
    m_unknown107Map[c] = m_unknown128Map[c] = m_unknown200Map[c] = unicode;
  }
  initAMap(s_centralEuroUnicode, sizeof(s_centralEuroUnicode)/(2*sizeof(int)), m_centralEuroMap);
  initAMap(s_cyrillicUnicode, sizeof(s_cyrillicUnicode)/(2*sizeof(int)), m_cyrillicMap);
  initAMap(s_turkishUnicode, sizeof(s_turkishUnicode)/(2*sizeof(int)), m_turkishMap);

  initAMap(s_symbolUnicode, sizeof(s_symbolUnicode)/(2*sizeof(int)), m_symbolMap);
  initAMap(s_dingbatsUnicode, sizeof(s_dingbatsUnicode)/(2*sizeof(int)), m_dingbatsMap);
  initAMap(s_cursiveIncompleteUnicode, sizeof(s_cursiveIncompleteUnicode)/(2*sizeof(int)), m_cursiveMap);
  initAMap(s_mathIncompleteUnicode, sizeof(s_mathIncompleteUnicode)/(2*sizeof(int)), m_mathMap);
  initAMap(s_scientificIncompleteUnicode, sizeof(s_scientificIncompleteUnicode)/(2*sizeof(int)),m_scientificMap);
  initAMap(s_wingdingsUnicode, sizeof(s_wingdingsUnicode)/(2*sizeof(int)), m_wingdingsMap);
  initAMap(s_SJISSimplifiedUnicode, sizeof(s_SJISSimplifiedUnicode)/(2*sizeof(int)), m_SJISMap);
  initAMap(s_unknown107IncompleteUnicode, sizeof(s_unknown107IncompleteUnicode)/(2*sizeof(int)),m_unknown107Map);
  initAMap(s_unknown128IncompleteUnicode, sizeof(s_unknown128IncompleteUnicode)/(2*sizeof(int)),m_unknown128Map);
  initAMap(s_unknown200IncompleteUnicode, sizeof(s_unknown200IncompleteUnicode)/(2*sizeof(int)),m_unknown200Map);

  // init convertMap
  m_convertMap[std::string("Default")] = &m_defaultConv;
  m_convertMap[std::string("Times")] = &m_timeConv;
  m_convertMap[std::string("Zapf Chancery")] = &m_zapfChanceryConv;
  m_convertMap[std::string("Symbol")] = &m_symbolConv;
  m_convertMap[std::string("Zapf Dingbats")] = &m_dingbatsConv;
  m_convertMap[std::string("Cursive")] = &m_cursiveConv;
  m_convertMap[std::string("Math")] = &m_mathConv;
  m_convertMap[std::string("scientific")] = &m_scientificConv;
  m_convertMap[std::string("Wingdings")] = &m_wingdingsConv;
  m_convertMap[std::string("Osaka")] = &m_SJISConv;
  m_convertMap[std::string("Unknown107")] = &m_unknown107Conv;
  m_convertMap[std::string("Unknown128")] = &m_unknown128Conv;
  m_convertMap[std::string("Unknown200")] = &m_unknown200Conv;

  m_familyMap["Osaka Tohaba"]="Osaka";
  m_familyMap["Hei"]="Osaka"; // checkme
  m_familyMap["Heisei Mincho"]="Osaka";
  m_familyMap["Heisei KakuGothic"]="Osaka";
  m_familyMap["Heiti SC Light"]="Osaka"; // checkme
  m_familyMap["Heiti SC Medium"]="Osaka"; // checkme
  m_familyMap["Hiragino KakuGothic ProN W3"]="Osaka";
  m_familyMap["Hiragino MaruGo W3"]="Osaka";
  m_familyMap["Hiragino MaruGo W4"]="Osaka";
  m_familyMap["Hiragino MaruGo W6"]="Osaka";
  m_familyMap["Hiragino Kakugo W3"]="Osaka";
  m_familyMap["Hiragino Kakugo W6"]="Osaka";
  m_familyMap["Hiragino Kakugo W8"]="Osaka";
  m_familyMap["Hiragino San GB W3"]="Osaka"; // checkme
  m_familyMap["Hiragino San GB W6"]="Osaka"; // checkme
}

ConversionData const &KnownConversion::getConversionMaps(std::string fName)
{
  if (fName.empty()) return m_defaultConv;
  std::map<std::string, ConversionData const *>::iterator it= m_convertMap.find(fName);
  if (it != m_convertMap.end()) return *(it->second);

  // look for a family map
  std::map<std::string, std::string>::iterator famIt= m_familyMap.find(fName);
  if (famIt == m_familyMap.end()) {
    // checkme maybe ok for pre-OS7, ... but not for WorldScript
    size_t len=fName.length();
    if (len > 4 && fName.substr(len-4,4)==" CYR")
      return m_cyrillicConv;
    if (len > 3 && fName[len-3]==' ') {
      if (fName.substr(len-3,3)==" CE")
        return m_centralEuroConv;
      if (fName.substr(len-3,3)==" CY")
        return m_cyrillicConv;
      if (fName.substr(len-3,3)==" TC")
        return m_turkishConv;
    }
    return m_defaultConv;
  }
  fName = famIt->second;
  it= m_convertMap.find(fName);
  if (it != m_convertMap.end()) return *(it->second);
  return  m_defaultConv;
}

}

//------------------------------------------------------------
//
// Font convertor imlementation
//
//------------------------------------------------------------
//! the default font converter
class State
{
public:
  //! the constructor
  State() : m_knownConversion(), m_idNameMap(), m_nameIdMap(),
    m_nameIdCounter(0), m_uniqueId(768), m_sjisConverter(), m_unicodeCache()
  {
    initMaps();
  }

  /** returns an unused id */
  int getUnusedId()
  {
    while (m_idNameMap.find(m_uniqueId)!=m_idNameMap.end())
      m_uniqueId++;
    return m_uniqueId;
  }

  /** returns the identificator for a name,
  if not set creates one */
  int getId(std::string const &name, std::string family="")
  {
    if (name.empty()) return -1;
    std::map<std::string,int>::iterator it=m_nameIdMap.find(name);
    if (it != m_nameIdMap.end()) return it->second;
    int newId=getUnusedId();
    setCorrespondance(newId, name, family);
    return newId;
  }

  //! returns the name corresponding to an id or return std::string("")
  std::string getName(int macId)
  {
    std::map<int, std::string>::iterator it=m_idNameMap.find(macId);
    if (it==m_idNameMap.end()) return "";
    return it->second;
  }

  /* converts a character in unicode
     \return -1 if the character is not transformed */
  int unicode(int macId, unsigned char c);
  /* converts a character in unicode, if needed can read the next input caracter
     \return -1 if the character is not transformed */
  int unicode(int macId, unsigned char c, MWAWInputStreamPtr &input);

  /** converts a character in unicode, if needed can read the next input caracter in str
      \return -1 if the character is not transformed */
  int unicode(int macId, unsigned char c, unsigned char const *(&str), int len);
  /** final font name and a delta which can be used to change the size
  if no name is found, return "Times New Roman" */
  void getOdtInfo(int macId, std::string &nm, int &deltaSize);

  //! fixes the name corresponding to an id
  void setCorrespondance(int macId, std::string const &name, std::string family="")
  {
    m_idNameMap[macId] = name;
    m_nameIdMap[name] = macId;
    m_nameIdCounter++;
    if (family.length())
      m_knownConversion.setFamily(name,family);
  }

protected:
  //! initializes the map
  void initMaps();
  //! try to update the cache
  bool updateCache(int macId);

  //! the basic conversion map
  MWAWFontConverterInternal::Data::KnownConversion m_knownConversion;
  //! map sysid -> font name
  std::map<int, std::string> m_idNameMap;
  //! map font name -> sysid
  std::map<std::string, int> m_nameIdMap;

  //!Internal: a counter modified when a new correspondance name<->id is found
  long m_nameIdCounter;

  //! a int used to create new id for a name
  int m_uniqueId;

  //! a SJIS convertor to convert Shit-JIS font
  shared_ptr<MWAWFontSJISConverter> m_sjisConverter;

  //! small structure to speedup unicode
  struct UnicodeCache {
    //! constructor
    UnicodeCache() : m_nameIdCounter(-1), m_macId(-1), m_conv(0) {}
    //! actual counter
    long m_nameIdCounter;
    //! actual macId
    int m_macId;
    //! actual convertor
    MWAWFontConverterInternal::Data::ConversionData const *m_conv;
  } m_unicodeCache;

};

// initializes the default conversion map
void State::initMaps()
{
  // see http://developer.apple.com/documentation/mac/Text/Text-277.html
  // or Apple II Technical Notes #41 (  http://www.umich.edu/~archive/apple2/technotes/tn/iigs/TN.IIGS.041 )
  // 0 system fonts, 1 appli fonts
  m_idNameMap[2] = "NewYork";
  m_idNameMap[3] = "Geneva";
  m_idNameMap[4] = "Monaco";
  m_idNameMap[5] = "Venice";
  m_idNameMap[6] = "London";
  m_idNameMap[7] = "Athens";
  m_idNameMap[8] = "SanFran";
  m_idNameMap[9] = "Toronto";

  m_idNameMap[11] = "Cairo";
  m_idNameMap[12] = "LosAngeles";
  m_idNameMap[13] = "Zapf Dingbats";
  m_idNameMap[14] = "Bookman";
  m_idNameMap[16] = "Palatino";
  m_idNameMap[18] = "Zapf Chancery";
  m_idNameMap[20] = "Times";
  m_idNameMap[21] = "Helvetica";
  m_idNameMap[22] = "Courier";
  m_idNameMap[23] = "Symbol";
  m_idNameMap[24] = "Mobile"; // or Taliesin: apple 2

  // ------- Apple II Technical Notes #41
  m_idNameMap[33] = "Avant Garde";
  m_idNameMap[34] = "New Century Schoolbook";

  // ------- Osnola: from a personal computer
  m_idNameMap[150] = "scientific";
  m_idNameMap[157] = "Cursive";
  m_idNameMap[201] = "Math";

  // ------- Osnola: unknown name
  m_idNameMap[107] = "Unknown107";
  m_idNameMap[128] = "Unknown128";
  m_idNameMap[200] = "Unknown200";

  // ------- fixme: find encoding
  m_idNameMap[174] = "Futura";
  m_idNameMap[258] = "ProFont";
  m_idNameMap[513] = "ISO Latin Nr 1";
  m_idNameMap[514] = "PCFont 437";
  m_idNameMap[515] = "PCFont 850";
  m_idNameMap[1029] = "VT80 Graphics";
  m_idNameMap[1030] = "3270 Graphics";
  m_idNameMap[1109] = "Trebuchet MS";
  m_idNameMap[1345] = "ProFont";
  m_idNameMap[1895] = "Nu Sans Regular";
  m_idNameMap[2001] = "Arial";
  m_idNameMap[2002] = "Charcoal";
  m_idNameMap[2004] = "Sand";
  m_idNameMap[2005] = "Courier New";
  m_idNameMap[2006] = "Techno";
  m_idNameMap[2010] = "Times New Roman";
  m_idNameMap[2011] = "Wingdings";
  m_idNameMap[2013] = "Hoefler Text";
  m_idNameMap[2018] = "Hoefler Text Ornaments";
  m_idNameMap[2039] = "Impact";
  m_idNameMap[2041] = "Mistral";
  m_idNameMap[2305] = "Textile";
  m_idNameMap[2307] = "Gadget";
  m_idNameMap[2311] = "Apple Chancery";
  m_idNameMap[2515] = "MT Extra";
  m_idNameMap[4513] = "Comic Sans MS";
  m_idNameMap[7092] = "Monotype.com";
  m_idNameMap[7102] = "Andale Mono";
  m_idNameMap[7203] = "Verdenal";
  m_idNameMap[9728] = "Espi Sans";
  m_idNameMap[9729] = "Charcoal";
  m_idNameMap[9840] = "Espy Sans/Copland";
  m_idNameMap[9841] = "Espy Sans/Bold";
  m_idNameMap[9842] = "Espy Sans Bold/Copland";
  m_idNameMap[10840] = "Klang MT";
  m_idNameMap[10890] = "Script MT Bold";
  m_idNameMap[10897] = "Old English Text MT";
  m_idNameMap[10909] = "New Berolina MT";
  m_idNameMap[10957] = "Bodoni MT Ultra Bold";
  m_idNameMap[10967] = "Arial MT Condensed Light";
  m_idNameMap[11103] = "Lydian MT";

  // japanese font ( check me )
  m_idNameMap[16384] = "Osaka";
  m_idNameMap[16436] = "Osaka Tohaba";
  m_idNameMap[16700] = "Heisei Mincho";
  m_idNameMap[16701] = "Heisei KakuGothic";
  m_idNameMap[16800] = "Hiragino KakuGothic ProN W3";
  m_idNameMap[28930] = "Hei";
  m_idNameMap[35934] = "Hiragino MaruGo W4";
  m_idNameMap[39129] = "Heiti SC Medium";
  m_idNameMap[48166] = "Hiragino Kakugo W3";
  m_idNameMap[48169] = "Hiragino Kakugo W6";
  m_idNameMap[54024] = "Hiragino Kakugo W8";
  m_idNameMap[55129] = "Hiragino San GB W6";
  m_idNameMap[55225] = "Hiragino San GB W3";
  m_idNameMap[62905] = "Heiti SC Light";
  m_idNameMap[64640] = "Hiragino MaruGo W3";
  m_idNameMap[64643] = "Hiragino MaruGo W6";

  std::map<int, std::string>::iterator it;
  for (it = m_idNameMap.begin(); it != m_idNameMap.end(); ++it)
    m_nameIdMap[it->second] = it->first;
}

// try to find the good converter
bool State::updateCache(int macId)
{
  if (!m_unicodeCache.m_conv || m_unicodeCache.m_macId != macId ||  m_unicodeCache.m_nameIdCounter != m_nameIdCounter) {
    m_unicodeCache.m_macId = macId;
    m_unicodeCache.m_nameIdCounter = m_nameIdCounter;
    m_unicodeCache.m_conv = &m_knownConversion.getConversionMaps(getName(macId));
  }
  if (!m_unicodeCache.m_conv) {
    MWAW_DEBUG_MSG(("unicode Error: can not find a convertor\n"));
    return false;
  }
  return true;
}

// returns an unicode caracter
int State::unicode(int macId, unsigned char c)
{
  if (!updateCache(macId))
    return -1;
  std::map<unsigned char, unsigned long>::const_iterator it = m_unicodeCache.m_conv->m_conversion.find(c);

  if (it == m_unicodeCache.m_conv->m_conversion.end()) return -1;
  return static_cast<int>(it->second);
}

// returns an unicode caracter
int State::unicode(int macId, unsigned char c, MWAWInputStreamPtr &input)
{
  if (!updateCache(macId))
    return -1;
  if (m_unicodeCache.m_conv->m_encoding==MWAWFontConverter::E_SJIS) {
    if (!m_sjisConverter)
      m_sjisConverter.reset(new MWAWFontSJISConverter);
    return m_sjisConverter->unicode(c,input);
  }

  std::map<unsigned char, unsigned long>::const_iterator it = m_unicodeCache.m_conv->m_conversion.find(c);
  if (it == m_unicodeCache.m_conv->m_conversion.end()) return -1;
  return static_cast<int>(it->second);
}

int State::unicode(int macId, unsigned char c, unsigned char const *(&str), int len)
{
  if (!updateCache(macId))
    return -1;
  if (m_unicodeCache.m_conv->m_encoding==MWAWFontConverter::E_SJIS) {
    if (!m_sjisConverter)
      m_sjisConverter.reset(new MWAWFontSJISConverter);
    return m_sjisConverter->unicode(c,str,len);
  }

  std::map<unsigned char, unsigned long>::const_iterator it = m_unicodeCache.m_conv->m_conversion.find(c);
  if (it == m_unicodeCache.m_conv->m_conversion.end()) return -1;
  return static_cast<int>(it->second);
}

void State::getOdtInfo(int macId, std::string &nm, int &deltaSize)
{
  std::string nam = getName(macId);
  MWAWFontConverterInternal::Data::ConversionData const *conv = &m_knownConversion.getConversionMaps(nam);

  nm = conv->m_name;
  deltaSize = conv->m_deltaSize;

  if (!nm.empty()) return;
  if (!nam.empty()) {
    nm = nam;
    return;
  }
#ifdef DEBUG
  static int lastUnknownId = -1;
  if (macId != lastUnknownId) {
    lastUnknownId = macId;
    MWAW_DEBUG_MSG(("MWAWFontConverterInternal::State::getOdtInfo: Unknown font with id=%d\n",macId));
  }
#endif
  nm = "Times New Roman";
}

}

MWAWFontConverter::MWAWFontConverter() : m_manager(new MWAWFontConverterInternal::State) { }
MWAWFontConverter::~MWAWFontConverter() {}

// mac font name <-> id functions
std::string MWAWFontConverter::getValidName(std::string const &name)
{
  std::string fName("");
  static bool first = true;
  for (size_t c = 0; c < name.length(); c++) {
    unsigned char ch = static_cast<unsigned char>(name[c]);
    if (ch > 0x1f && ch < 0x80) {
      fName+=name[c];
      continue;
    }
    if (first) {
      MWAW_DEBUG_MSG(("MWAWFontConverter::getValidName: fontName contains bad character\n"));
      first = false;
    }
    fName += 'X';
  }
  return fName;
}

void MWAWFontConverter::setCorrespondance(int macId, std::string const &name, std::string family)
{
  m_manager->setCorrespondance(macId, getValidName(name), family);
}

int MWAWFontConverter::getId(std::string const &name, std::string family)  const
{
  return m_manager->getId(getValidName(name), family);
}

std::string MWAWFontConverter::getName(int macId) const
{
  return m_manager->getName(macId);
}

void MWAWFontConverter::getOdtInfo(int macId, std::string &nm, int &deltaSize) const
{
  m_manager->getOdtInfo(macId, nm, deltaSize);
}

int MWAWFontConverter::unicode(int macId, unsigned char c) const
{
  if (c < 0x20) return -1;
  return m_manager->unicode(macId, c);
}

int MWAWFontConverter::unicode(int macId, unsigned char c, MWAWInputStreamPtr &input) const
{
  if (c < 0x20) return -1;
  return m_manager->unicode(macId,c,input);
}

int MWAWFontConverter::unicode(int macId, unsigned char c, unsigned char const *(&str), int len) const
{
  if (c < 0x20) return -1;
  return m_manager->unicode(macId,c,str,len);
}
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
