2005/5/9

     
 

Encoding.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/locale/Encoding.cpp,v 1.20 2005/04/28 14:58:14 kommer Exp $

#include "Encoding.h"
#include "CEscapeEncoding.h"
#include "AsciiUtfEncoding.h"

#include "AsciiEncoding.h"
#include "UnmappableCharacterException.h"

#include <acdk/io/Writer.h>
#include <acdk/lang/System.h>

namespace acdk {
namespace locale {


Encoder::Encoder(IN(REncoding) encoding, CodingErrorAction onMalformed, CodingErrorAction onUnmappable)
: _encoding(encoding)
, _onMalformedInput(onMalformed)
, _onUnmappableCharacter(onUnmappable)
, _bytesWritten(0)
{
}

void 
Encoder::handleUnmappable(IN(acdk::io::RWriter) out, uc2char ch)
{
  switch (unmappableCharacterAction())
  {
  case IgnoreCodingError:
    return;
  case ReplaceCodingError:
  {
    RbyteArray ba = getEncodingReplacement();
    if (ba != Nil)
      out->write(ba);
    break;
  }
  case ReportCodingError:
    THROW1(UnmappableCharacterException, getEncoding()->getName() + ": cannot encode : " + String::valueOf(ch));
  }
}

RString 
Decoder::handleUnmappable(uc2char ch)
{
  switch (unmappableCharacterAction())
  {
  case IgnoreCodingError:
    return "";
  case ReplaceCodingError:
  {
    RString s = getDecodingReplacement();
    if (s != Nil)
      return s;
    return "";
  }
  case ReportCodingError:
    THROW1(UnmappableCharacterException, getEncoding()->getName() + ": cannot encode : " + String::valueOf(ch));
  }
  return "";
}


Decoder::Decoder(IN(REncoding) encoding, CodingErrorAction onMalformed, CodingErrorAction onUnmappable)
: _onMalformedInput(onMalformed)
, _onUnmappableCharacter(onUnmappable)
, _encoding(encoding)
, _bytesReaded(0)
{
}

namespace {

struct EncSlot
{
  RString name; 
  EncodingCreator creator;
  EncSlot(IN(RString) n, EncodingCreator c) : name(n), creator(c) {}
  EncSlot() : name(Nil), creator(0) {}
};

typedef ::acdk::lang::sys::core_vector<EncSlot> Encoders;


Encoders& 
getEncoders()
{
  static Encoders _encoders(0);
  return _encoders;
}


} // anon namespace
//static 
void 
Encoding::registerEncoding(IN(RString) name, EncodingCreator creator)
{
  getEncoders().push_back(EncSlot(name, creator));
  System::registerStaticReference(getEncoders().back().name);
}

OUT(REncoding)
Encoding_getStaticEncoding()
{
  static REncoding staticEncoding;
  return staticEncoding;
}

//static 
REncoding 
Encoding::getEncoding() THROWS1(RIllegalCharsetNameException)
{
  OUT(REncoding) enc =  Encoding_getStaticEncoding();
  if (enc != Nil)
    return enc;
  RString encName = System::getProperties()->getProperty("user.encoding");
  if (encName == Nil)
    enc = getAsciiEncoding();
  else
  {
    enc = findEncoding(encName);
    if (enc == Nil && encName->startsWith("1") == true)
      enc = findEncoding("CP" + encName);
    if (enc == Nil)
    {
      RString encodings = String::join((RObjectArray)getAvailableEncodings(), ", "); /** add template function String::join for ObjectArrays */
      THROW1(IllegalCharsetNameException, "Unknown Encoding: " + encName + ". Select one of: " + encodings);
    }
  }
  return enc;
}

void
Encoding::setEncoding(IN(REncoding) encoding)
{
  Encoding_getStaticEncoding() = encoding;
}

REncoding 
Encoding::findEncoding(IN(RString) name)
{
  Encoders& encs = getEncoders();
  Encoders::iterator it = encs.begin();
  Encoders::iterator end = encs.end();
  for (; it != end; ++it)
  {
    if (it->name->equalsIgnoreCase(name) == true)
      return it->creator(name);
  }
  return Nil;
}


//static 
REncoding 
Encoding::getEncoding(IN(RString) name) THROWS1(RIllegalCharsetNameException)
{
  REncoding enc = findEncoding(name);
  if (enc != Nil)
    return enc;
  RString encodings = String::join((RObjectArray)getAvailableEncodings(), ", ");
  THROW1(IllegalCharsetNameException, "Unknown Encoding: " + name + ". Select one of: " + encodings);
  return Nil;
}

//static 
RStringArray 
Encoding::getAvailableEncodings()
{
  Encoders& encs = getEncoders();
  RStringArray erg = new StringArray(encs.size());
  Encoders::iterator it = encs.begin();
  Encoders::iterator end = encs.end();
  for (int i = 0; it != end; ++it, ++i)
  {
    erg[i] = it->name;
  }
  return erg;
}

/*
RString 
Encoding::decode(IN(RString) str)
{
  RuccharArray ba = _decoder->decode((byte*)str->byte_begin(), (byte*)str->byte_end());
  return new String(ba);
}

RString 
Encoding::encode(IN(RString) str)
{
  // ### TODO RbyteArray ca = _encoder->encode(str->begin(), str->end(), true);
  //return new String(ca);
  return Nil;
}





*/

//static 
REncoding 
Encoding::getCEscapeEncoding()
{
  return &CEscapeEncoding::_encoder;
}

//static 
REncoding 
Encoding::getAsciiEncoding()
{
  return AsciiEncoding::getAsciiEncoding();
}

REncoding 
Encoding::getUnicodeEscapeEncoding()
{
  return AsciiUtfEncoding::getAsciiUtfEncoding();
}

//static 
REncoding 
Encoding::getUnicodeCEscapeEncoding()
{
  return AsciiUtfEncoding::getAsciiUtfCEscapeEncoding();
}


UnmappableCharacterException::UnmappableCharacterException() 
: CharacterCodingException() 
{
    //int* ptr = 0;
    //*ptr = 42;
}

UnmappableCharacterException::UnmappableCharacterException(IN(RString) what) 
: CharacterCodingException(what) 
{
    //int* ptr = 0;
    //*ptr = 42;
}



} // locale
} // acdk