Esempio n. 1
0
ULONG TextType::canonical(ULONG srcLen, const UCHAR* src, ULONG dstLen, UCHAR* dst)
{
	if (tt->texttype_fn_canonical)
		return (*tt->texttype_fn_canonical)(tt, srcLen, src, dstLen, dst);

	if (getCharSet()->isMultiByte())
	{
		fb_assert(tt->texttype_canonical_width == sizeof(ULONG));

		Firebird::HalfStaticArray<UCHAR, BUFFER_SMALL> utf16_str;

		ULONG utf16_len = getCharSet()->getConvToUnicode().convertLength(srcLen);

		// convert to UTF-16
		utf16_len = getCharSet()->getConvToUnicode().convert(srcLen, src,
			utf16_len, utf16_str.getBuffer(utf16_len));

		USHORT errCode;
		ULONG errPos;

		// convert UTF-16 to UTF-32
		return UnicodeUtil::utf16ToUtf32(utf16_len, Firebird::Aligner<USHORT>(utf16_str.begin(), utf16_len),
			dstLen, Firebird::OutAligner<ULONG>(dst, dstLen), &errCode, &errPos) / sizeof(ULONG);
	}

	fb_assert(
		(tt->texttype_canonical_width == 0 && !tt->texttype_fn_canonical) ||
		tt->texttype_canonical_width == getCharSet()->minBytesPerChar());
	fb_assert(dstLen >= srcLen);

	memcpy(dst, src, srcLen);

	return srcLen / getCharSet()->minBytesPerChar();
}
Esempio n. 2
0
/**
 * Creates a plain text (or html) email and 
 * specifies the necessary MIME types if needed
 * due to attaching base64 files.
 * when this function is done, it will rewind
 * the file position and return an open file
**/
static dstrbuf *
createPlainEmail(dstrbuf *msg) 
{
	dstrbuf *border=NULL;
	dstrbuf *buf=DSB_NEW;
	CharSetType cs;

	if (Mopts.attach) {
		border = mimeMakeBoundary();
	} else {
		border = DSB_NEW;
	}

	if (Mopts.encoding) {
		cs = getCharSet((u_char *)msg->str);
	} else {
		cs = IS_ASCII;
	}
	printHeaders(border->str, buf, cs);
	if (makeMessage(msg, buf, border->str, cs) < 0) {
		dsbDestroy(buf);
		buf=NULL;
	}
	dsbDestroy(border);
	return buf;
}
Esempio n. 3
0
ULONG TextType::str_to_lower(ULONG srcLen, const UCHAR* src, ULONG dstLen, UCHAR* dst)
{
	if (tt->texttype_fn_str_to_lower)
		return (*tt->texttype_fn_str_to_lower)(tt, srcLen, src, dstLen, dst);

	return Firebird::IntlUtil::toLower(getCharSet(), srcLen, src, dstLen, dst, NULL);
}
Esempio n. 4
0
USHORT TextType::string_to_key(USHORT srcLen, const UCHAR* src,
							   USHORT dstLen, UCHAR* dst,
							   USHORT key_type)
{
	if (tt->texttype_fn_string_to_key)
		return (*tt->texttype_fn_string_to_key)(tt, srcLen, src, dstLen, dst, key_type);

	const UCHAR* space = getCharSet()->getSpace();
	BYTE spaceLength = getCharSet()->getSpaceLength();
	Firebird::HalfStaticArray<UCHAR, BUFFER_SMALL> utf16Str;
	UCHAR utf16Space[sizeof(ULONG)];

	if (getCharSet()->isMultiByte())
	{
		// convert src to UTF-16
		const ULONG utf16Length = getCharSet()->getConvToUnicode().convertLength(srcLen);

		srcLen = getCharSet()->getConvToUnicode().convert(srcLen, src,
					utf16Length, utf16Str.getBuffer(utf16Length));
		src = utf16Str.begin();

		// convert charset space to UTF-16
		spaceLength =
			getCharSet()->getConvToUnicode().convert(spaceLength, space, sizeof(utf16Space), utf16Space);
		fb_assert(spaceLength == 2);	// space character can't be surrogate for default string_to_key
		space = utf16Space;
	}

	if (tt->texttype_pad_option)
	{
		const UCHAR* pad;

		for (pad = src + srcLen - spaceLength; pad >= src; pad -= spaceLength)
		{
			if (memcmp(pad, space, spaceLength) != 0)
				break;
		}

		srcLen = pad - src + spaceLength;
	}

	if (getCharSet()->isMultiByte())
	{
		dstLen = UnicodeUtil::utf16ToKey(srcLen, Firebird::Aligner<USHORT>(src, srcLen), dstLen, dst);
	}
	else
	{
		if (dstLen >= srcLen)
		{
			memcpy(dst, src, srcLen);
			dstLen = srcLen;
		}
		else
			dstLen = INTL_BAD_KEY_LENGTH;
	}

	return dstLen;
}
Esempio n. 5
0
USHORT TextType::key_length(USHORT len)
{
	if (tt->texttype_fn_key_length)
		return (*tt->texttype_fn_key_length)(tt, len);

	if (getCharSet()->isMultiByte())
		return UnicodeUtil::utf16KeyLength(len);

	return len;
}
Esempio n. 6
0
/**
 * This function takes the current content that was copied
 * in to us and creates a final message with the email header
 * and the appended content.  It will also attach any files
 * that were specified at the command line.
**/
static void
printHeaders(const char *border, dstrbuf *msg, CharSetType msg_cs)
{
	char *subject=Mopts.subject;
	char *user_name = getConfValue("MY_NAME");
	char *email_addr = getConfValue("MY_EMAIL");
	char *sm_bin = getConfValue("SENDMAIL_BIN");
	char *smtp_serv = getConfValue("SMTP_SERVER");
	char *reply_to = getConfValue("REPLY_TO");
	dstrbuf *dsb=NULL;

	if (subject) {
		if (Mopts.encoding) {
			CharSetType cs = getCharSet((u_char *)subject);
			if (cs == IS_UTF8) {
				dsb = encodeUtf8String((u_char *)subject, false);
				subject = dsb->str;
			} else if (cs == IS_PARTIAL_UTF8) {
				dsb = encodeUtf8String((u_char *)subject, true);
				subject = dsb->str;
			}
		}
		dsbPrintf(msg, "Subject: %s\r\n", subject);
		if (dsb) {
			dsbDestroy(dsb);
		}
	}
	printFromHeaders(user_name, email_addr, msg);
	printToHeaders(Mopts.to, Mopts.cc, msg);

	/**
	 * We want to check here to see if we are sending mail by invoking sendmail
	 * If so, We want to add the BCC line to the headers.  Sendmail checks this
	 * Line and makes sure it sends the mail to the BCC people, and then remove
	 * the BCC addresses...  Keep in mind that sending to an smtp servers takes
	 * presidence over sending to sendmail incase both are mentioned.
	 */
	if (sm_bin && !smtp_serv) {
		printBccHeaders(Mopts.bcc, msg);
	}

	/* The rest of the standard headers */
	printDateHeaders(msg);
	if (reply_to) {
		dsbPrintf(msg, "Reply-To: <%s>\r\n", reply_to);
	}
	printMimeHeaders(border, msg, msg_cs);
	dsbPrintf(msg, "X-Mailer: Cleancode.email v%s \r\n", EMAIL_VERSION);
	if (Mopts.priority) {
		dsbPrintf(msg, "X-Priority: 1\r\n");
	}
	printExtraHeaders(Mopts.headers, msg);
	dsbPrintf(msg, "\r\n");
}
Esempio n. 7
0
char* Param::getDisplayValue(CharInfo::CharSet display_cs) 
{
  if ( isInSingleByteForm() == FALSE && getCharSet() == CharInfo::UNICODE ) {
       
    if ( display_value == NULL ) 
    {
       NAWchar* wvalue = (NAWchar*)value;
       Lng32 wlen = (Lng32)NAWstrlen(wvalue);
       display_value = new char[wlen+1];
       UnicodeStringToLocale(display_cs, wvalue, wlen, 
                             display_value, wlen+1,
                             TRUE, // add null at end 
                             TRUE  // non-convertable char to ? 
                            );
    }
    return display_value;

  } else
   return getValue();
}
Esempio n. 8
0
short Param::convertValue(SqlciEnv * sqlci_env, short targetType,
			  Lng32 &targetLen,
			  Lng32 targetPrecision,
			  Lng32 targetScale,
                          Lng32 vcIndLen,
   			  ComDiagsArea* diags) {

  // get rid of the old converted value
  if (converted_value) {
    delete [] converted_value;
    converted_value = 0;
  };

  short sourceType;
  Lng32 sourceLen;

  // set up the source and its length based on the how the value is passed-in.
  if ( isInSingleByteForm() == FALSE ) {
    sourceLen = (Lng32)(NAWstrlen((NAWchar*)value) * BYTES_PER_NAWCHAR);
    switch (getCharSet()) {
      case CharInfo::UNICODE:
        sourceType = REC_NCHAR_F_UNICODE;
        break;

      case CharInfo::KANJI_MP:
      case CharInfo::KSC5601_MP:
        sourceType = REC_BYTE_F_ASCII; // KANJI/KSC passed in as NAWchar*
        break;

      default:
        return SQL_Error; // error case
    }
  } else {
    sourceLen = (Lng32)strlen(value); // for any source in single-byte format
    sourceType = REC_BYTE_F_ASCII;
  }

  char * pParamValue = value;

  if ( DFS2REC::isAnyCharacter(targetType) ) {

    if (termCS_ == CharInfo::UnknownCharSet)
      termCS_ = sqlci_env->getTerminalCharset();
    if (cs == CharInfo::UnknownCharSet)
    {
      isQuotedStrWithoutCharSetPrefix_ = TRUE;
      cs = termCS_;
    }

    // If the target is CHARACTER and param is set as [_cs_prefix]'...', then 
    // make sure the source is assignment compatible with the target.
    CharInfo::CharSet targetCharSet = (CharInfo::CharSet)targetScale;
    if ( targetCharSet == CharInfo::UNICODE )
    {
      if (getUTF16StrLit() == (NAWchar*)NULL)
      {
        utf16StrLit_ = new NAWchar [ sourceLen * 2 + 1 ]; // plenty of room
        Lng32 utf16StrLenInNAWchars =
          LocaleStringToUnicode(cs/*sourceCS*/, /*sourceStr*/value, sourceLen,
                                utf16StrLit_/*outputBuf*/, sourceLen+1/*outputBufSizeInNAWchars*/,
                                TRUE /* in - NABoolean addNullAtEnd*/);
        if (sourceLen > 0 && utf16StrLenInNAWchars == 0)
          return SQL_Error;

        // ComASSERT(utf16StrLenInNAWchars == NAWstrlen(getUTF16StrLit()));
        // Resize the NAWchar buffer to save space
        NAWchar *pNAWcharBuf = new NAWchar [ utf16StrLenInNAWchars + 1 ];
        NAWstrncpy (pNAWcharBuf, utf16StrLit_, utf16StrLenInNAWchars + 1);
        pNAWcharBuf[utf16StrLenInNAWchars] = NAWCHR('\0'); // play it safe
        delete [] utf16StrLit_;
        utf16StrLit_ = pNAWcharBuf; // do not deallocate pNAWcharBuf
      }
      sourceLen = (Lng32)(NAWstrlen(getUTF16StrLit()) * BYTES_PER_NAWCHAR);
      // check to see if the parameter utf16 string fits in the target
      if ( sourceLen > targetLen )
        return SQL_Error;

      pParamValue = (char *)getUTF16StrLit();
      sourceType = REC_NCHAR_F_UNICODE;
    }

  } else {
 
    // MP NCHAR (KANJI/KSC) can not be converted to non-character objects
   if ( CharInfo::is_NCHAR_MP(cs) )
      return SQL_Error;
  }


  switch(targetType) {
  case REC_BIN16_SIGNED:
  case REC_BIN16_UNSIGNED:
  case REC_BPINT_UNSIGNED:
  case REC_BIN32_SIGNED:
  case REC_BIN32_UNSIGNED:
  case REC_BIN64_SIGNED:
  case REC_DECIMAL_UNSIGNED:
  case REC_DECIMAL_LSE:
  case REC_FLOAT32:
  case REC_FLOAT64:
  case REC_TDM_FLOAT32:
  case REC_TDM_FLOAT64:
  case REC_BYTE_F_ASCII:
  case REC_BYTE_V_ASCII:
  case REC_BYTE_V_ASCII_LONG:
  case REC_NCHAR_F_UNICODE:
  case REC_NCHAR_V_UNICODE:
  {
    char *VCLen = NULL;
    short VCLenSize = 0;

// 5/27/98: added VARNCHAR cases
    if ((targetType == REC_BYTE_V_ASCII) || 
        (targetType == REC_BYTE_V_ASCII_LONG) ||
        (targetType == REC_NCHAR_V_UNICODE)) 
    {
      // add bytes for variable length field
      VCLenSize = vcIndLen; //sizeof(short);
      VCLen = converted_value = new char[targetLen + VCLenSize];
    } else
      converted_value = new char[targetLen];


#pragma nowarn(1506)   // warning elimination 
    ex_expr::exp_return_type ok;
    CharInfo::CharSet TCS = sqlci_env->getTerminalCharset();
    CharInfo::CharSet ISOMAPCS = sqlci_env->getIsoMappingCharset();
    
    NAString* tempstr;
    if ( 
        DFS2REC::isAnyCharacter(sourceType) && DFS2REC::isAnyCharacter(targetType) &&
        !(getUTF16StrLit() != NULL && sourceType == REC_NCHAR_F_UNICODE && targetScale == CharInfo::UCS2) &&
        /*source*/cs != targetScale/*i.e., targetCharSet*/
        )
    {
      charBuf cbuf((unsigned char*)pParamValue, sourceLen);
      NAWcharBuf* wcbuf = 0;
      Int32 errorcode = 0;
      wcbuf = csetToUnicode(cbuf, 0, wcbuf,
                            cs/*sourceCharSet*/
                            , errorcode);
      if (errorcode != 0) return SQL_Error;
      tempstr = unicodeToChar(wcbuf->data(),wcbuf->getStrLen(),
                              targetScale/*i.e., targetCharSet*/
                              );
      if (tempstr == NULL) 
	return SQL_Error;  //Avoid NULL ptr reference if conversion error
      sourceType = targetType; // we just converted it to the target type
      sourceLen = tempstr->length();
      pParamValue = (char *)tempstr->data();

      if ( sourceLen > targetLen )
        return SQL_Error;
    }

    ok = convDoIt(pParamValue,
		  sourceLen, 
		  sourceType,
		  0, // source Precision
		  targetScale, // new charset we converted to
		  &converted_value[VCLenSize],
		  targetLen,
		  targetType,
		  targetPrecision,
		  targetScale,
		  VCLen,
		  VCLenSize,
		  0,
		  &diags);
    
    if ( ok != ex_expr::EXPR_OK)
    {
      // No need to delete allocated memory before return because class member
      // converted_value still points to allocated memory that is deleted in 
      // desctructor.
      return SQL_Error; // error case
    }
#pragma warn(1506)  // warning elimination
    
  };
  break;


  case REC_DATETIME: {

    char *VCLen = NULL;
    short VCLenSize = 0;
    converted_value = new char[targetLen + 1];

#pragma nowarn(1506)   // warning elimination 
    ex_expr::exp_return_type ok = convDoIt(value,
					   sourceLen, 
					   sourceType,
					   0, // source Precision
					   0, // source Scale
					   converted_value,
					   targetLen,
					   targetType,
					   targetPrecision,
					   targetScale,
					   VCLen,
					   VCLenSize,
					   0,
					   &diags);
    
    if ( ok != ex_expr::EXPR_OK)
      {
	return SQL_Error; // error case
      }
#pragma warn(1506)  // warning elimination
  };
  break;

  case REC_INT_YEAR:
  case REC_INT_MONTH:
  case REC_INT_YEAR_MONTH:
  case REC_INT_DAY:
  case REC_INT_HOUR:
  case REC_INT_DAY_HOUR:
  case REC_INT_MINUTE:
  case REC_INT_HOUR_MINUTE:
  case REC_INT_DAY_MINUTE:
  case REC_INT_SECOND:
  case REC_INT_MINUTE_SECOND:
  case REC_INT_HOUR_SECOND:
  case REC_INT_DAY_SECOND: {

    // convert target back to string.
    converted_value = new char[targetLen];
    Lng32 convFlags = CONV_ALLOW_SIGN_IN_INTERVAL;
#pragma nowarn(1506)   // warning elimination 
    short ok = 
      convDoItMxcs(value,
		   sourceLen, 
		   sourceType,
		   0, // source Precision
		   0, // source Scale
		   converted_value,
		   targetLen,
		   targetType,
		   targetPrecision,
		   targetScale,
		   convFlags);
    
    if ( ok != 0 )
    {
      // No need to delete allocated memory before return because class member
      // converted_value still points to allocated memory that is deleted in 
      // desctructor.
      return SQL_Error; // error case
    }
#pragma warn(1506)  // warning elimination
  };
  break;

  case REC_NUM_BIG_UNSIGNED:
  case REC_NUM_BIG_SIGNED:
  {
    converted_value = new char[targetLen];
#pragma nowarn(1506)   // warning elimination 
    short ok = 
      convDoItMxcs(value,
		   sourceLen, 
		   sourceType,
		   0, // source Precision
		   0, // source Scale
		   converted_value,
		   targetLen,
		   targetType,
		   targetPrecision,
		   targetScale,
		   0);
    
    if ( ok != 0 )
    {
      // No need to delete allocated memory before return because class member
      // converted_value still points to allocated memory that is deleted in 
      // desctructor.
      return SQL_Error; // error case
    }
#pragma warn(1506)  // warning elimination
    
  };
  break;

  default:
    break;
  };

  return 0;
}
Esempio n. 9
0
File: submit.c Progetto: juddy/edcde
static char *
formatMessage(char ** addrs, const char * subject, const char * body)
{
    char * 	msg;
    int		size = 0;
    int		line;
    char **	to;
    int isAllASCII;
    char hdr_buf[1024];
    _DtXlateDb db = NULL;
    char plat[_DtPLATFORM_MAX_LEN];
    int execver;
    int compver;
    int body_len;
    char digest[16];
    char mime_type[64];
    char tmpbuf[20];
    char *ret_locale = NULL;
    char *ret_lang = NULL;
    char *ret_codeset = NULL;
    char default_charset[64];
    char *NewBuf = NULL;
    unsigned long _len = 0;
    Encoding enc;

    /* Figure out how big we need the buffer to be. */
    for (to = addrs; *to; to++) {
	size += strlen(*to);
	size += 2; /* Leave room for the , */
    }

    size += strlen(subject);
    size += strlen(body);

    /* We will need space for the header names, a blank line, and
       other general formatting things. We could be exact, but
       1024 is more than enough and give us some spare.
       */
    size += 1024;

    msg = (char *)malloc(size);

    strcpy(msg, "To: ");
    line = 4;

    for (to = addrs; *to; to++) {
	strcat(msg, *to);
	if (*(to + 1) != NULL) {
	    strcat(msg, ", ");
	    line += strlen(*to);
	    if (line > 72) {
		strcat(msg, "\n    ");
		line = 0;
	    }
	}
    }
    strcat(msg, "\nSubject: ");

    /* Encode the body of the message */
    
    /* 1) Open Lcx data bases */

    if ((_DtLcxOpenAllDbs(&db) == 0) &&
        (_DtXlateGetXlateEnv(db,plat,&execver,&compver) != 0))
	{
		_DtLcxCloseDb(&db);
    		strcat(msg, subject);
    		if (msg[strlen(msg) - 1] == '\n') {
			msg[strlen(msg) - 1] = 0;
    		}

    		strcat(msg, "\nMime-Version: 1.0\n");
    		strcat(msg, "Content-Type: text/plain;charset=us-ascii\n\n");
    		strcat(msg, body);
	}
    else
	{

		body_len = strlen(body);

		hdr_buf[0]='\0';
		
		strcpy(mime_type,"text/plain");
		rfc1522cpy(hdr_buf,subject);	
		strcat(hdr_buf,"Mime-Version: 1.0\n");
		isAllASCII= CvtStr((char *)NULL,(void *)body,(unsigned long)body_len,(void**)&NewBuf, &_len, CURRENT_TO_INTERNET);

		enc = getEncodingType(body,body_len,FALSE);
       /*
         * Here is an ugly adjustment again. If mime_type is text/plain and if
         * ret_codeset is ISO-2022-JP/KR/TW/CN, we have to always use
         * enc = MIME_7BIT
         * This means if the user inputs UDC/VDC into the e-mail body,
         * fold7 may convert it to the string with MSB-on character and
         * dtmail passes it to sendmail as if I had all 7bit chars.
         */
		getCharSet(default_charset);
		DtXlateOpToStdLocale(DtLCX_OPER_MIME, default_charset,
					&ret_locale, &ret_lang, &ret_codeset);
            	if ( !strncasecmp( mime_type, "text/plain", 10 ) &&
                 ( !strncasecmp( ret_codeset, "ISO-2022-JP", 11 ) ||
                   !strncasecmp( ret_codeset, "ISO-2022-KR", 11 ) ||
                   !strncasecmp( ret_codeset, "ISO-2022-TW", 11 ) ||
                   !strncasecmp( ret_codeset, "ISO-2022-CN", 11 )   ) ) 
                	enc = MIME_7BIT;

		memset(digest,0,sizeof(digest));
		md5PlainText(body,body_len,digest);
		writeContentHeaders(hdr_buf,mime_type,enc,(char *)digest,isAllASCII);
		strcat(hdr_buf,"\n");
		strcat(hdr_buf,"Content-Length: ");
		if (( NewBuf != NULL) && ( _len != 0))
		{
			sprintf(tmpbuf,"%ld",_len);
			strcat(hdr_buf,tmpbuf);
			strcat(hdr_buf,"\n");
			strcat(msg,hdr_buf);
			strncat(msg,NewBuf,_len);
			strcat(hdr_buf,"\n");
		}
		else
		{
			sprintf(tmpbuf,"%d",body_len);
			strcat(hdr_buf,tmpbuf);
			strcat(hdr_buf,"\n");
			strcat(msg,hdr_buf);
			strcat(msg,body);
		}
	}


    return(msg);
}
Esempio n. 10
0
SSHORT TextType::compare(ULONG len1, const UCHAR* str1, ULONG len2, const UCHAR* str2)
{
	INTL_BOOL error = false;

	if (tt->texttype_fn_compare)
		return (*tt->texttype_fn_compare)(tt, len1, str1, len2, str2, &error);

	const UCHAR* space = getCharSet()->getSpace();
	BYTE spaceLength = getCharSet()->getSpaceLength();
	Firebird::HalfStaticArray<UCHAR, BUFFER_SMALL> utf16Str1;
	Firebird::HalfStaticArray<UCHAR, BUFFER_SMALL> utf16Str2;
	UCHAR utf16Space[sizeof(ULONG)];

	if (getCharSet()->isMultiByte())
	{
		// convert str1 to UTF-16
		ULONG utf16Length = getCharSet()->getConvToUnicode().convertLength(len1);

		len1 = getCharSet()->getConvToUnicode().convert(len1, str1,
					utf16Length, utf16Str1.getBuffer(utf16Length));
		str1 = utf16Str1.begin();

		// convert str2 to UTF-16
		utf16Length = getCharSet()->getConvToUnicode().convertLength(len2);

		len2 = getCharSet()->getConvToUnicode().convert(len2, str2,
					utf16Length, utf16Str2.getBuffer(utf16Length));
		str2 = utf16Str2.begin();

		// convert charset space to UTF-16
		spaceLength =
			getCharSet()->getConvToUnicode().convert(spaceLength, space, sizeof(utf16Space), utf16Space);
		fb_assert(spaceLength == 2);	// space character can't be surrogate for default compare
		space = utf16Space;
	}

	if (tt->texttype_pad_option)
	{
		const UCHAR* pad;

		for (pad = str1 + len1 - spaceLength; pad >= str1; pad -= spaceLength)
		{
			if (memcmp(pad, space, spaceLength) != 0)
				break;
		}

		len1 = pad - str1 + spaceLength;

		for (pad = str2 + len2 - spaceLength; pad >= str2; pad -= spaceLength)
		{
			if (memcmp(pad, space, spaceLength) != 0)
				break;
		}

		len2 = pad - str2 + spaceLength;
	}

	if (getCharSet()->isMultiByte())
	{
		INTL_BOOL error_flag;
		return UnicodeUtil::utf16Compare(len1, Firebird::Aligner<USHORT>(str1, len1),
										 len2, Firebird::Aligner<USHORT>(str2, len2), &error_flag);
	}

	SSHORT cmp = memcmp(str1, str2, MIN(len1, len2));

	if (cmp == 0)
		cmp = (len1 < len2 ? -1 : (len1 > len2 ? 1 : 0));

	return cmp;
}
Esempio n. 11
0
TextType::TextType(TTYPE_ID _type, texttype *_tt, CharSet* _cs)
	: tt(_tt), cs(_cs), type(_type)
{
	canonical(cs->getSqlMatchAnyLength(), cs->getSqlMatchAny(),
		sizeof(ULONG), reinterpret_cast<UCHAR*>(&canonicalChars[CHAR_SQL_MATCH_ANY]));
	canonical(cs->getSqlMatchOneLength(), cs->getSqlMatchOne(),
		sizeof(ULONG), reinterpret_cast<UCHAR*>(&canonicalChars[CHAR_SQL_MATCH_ONE]));

	struct Conversion
	{
		USHORT code;
		int ch;
	};

	const Conversion conversions[] =
		{
			{'*', CHAR_ASTERISK},
			{'@', CHAR_AT},
			{'^', CHAR_CIRCUMFLEX},
			{':', CHAR_COLON},
			{',', CHAR_COMMA},
			{'=', CHAR_EQUAL},
			{'-', CHAR_MINUS},
			{'%', CHAR_PERCENT},
			{'+', CHAR_PLUS},
			{'?', CHAR_QUESTION_MARK},
			{' ', CHAR_SPACE},
			{'~', CHAR_TILDE},
			{'_', CHAR_UNDERLINE},
			{'|', CHAR_VERTICAL_BAR},
			{'{', CHAR_OPEN_BRACE},
			{'}', CHAR_CLOSE_BRACE},
			{'[', CHAR_OPEN_BRACKET},
			{']', CHAR_CLOSE_BRACKET},
			{'(', CHAR_OPEN_PAREN},
			{')', CHAR_CLOSE_PAREN},
			{'s', CHAR_LOWER_S},
			{'S', CHAR_UPPER_S}
		};

	for (int i = 0; i < FB_NELEM(conversions); i++)
	{
		UCHAR temp[sizeof(ULONG)];

		ULONG length = getCharSet()->getConvFromUnicode().convert(
			sizeof(USHORT), &conversions[i].code, sizeof(temp), temp);
		canonical(length, temp, sizeof(ULONG),
			reinterpret_cast<UCHAR*>(&canonicalChars[conversions[i].ch]));
	}

	struct Conversion2
	{
		const char* str;
		UCHAR* buffer;
	};

	const Conversion2 conversions2[] =
	{
		{"0123456789", reinterpret_cast<UCHAR*>(canonicalNumbers)},
		{"abcdefghijklmnopqrstuvwxyz", reinterpret_cast<UCHAR*>(canonicalLowerLetters)},
		{"ABCDEFGHIJKLMNOPQRSTUVWXYZ", reinterpret_cast<UCHAR*>(canonicalUpperLetters)},
		{" \t\v\r\n\f", reinterpret_cast<UCHAR*>(canonicalWhiteSpaces)}
	};

	for (int i = 0; i < FB_NELEM(conversions2); i++)
	{
		UCHAR temp[sizeof(ULONG)];

		for (const char* p = conversions2[i].str; *p; ++p)
		{
			USHORT code = static_cast<USHORT>(*p);
			ULONG length = getCharSet()->getConvFromUnicode().convert(sizeof(code), &code, sizeof(temp), temp);
			const size_t pos = (p - conversions2[i].str) * getCanonicalWidth();
			canonical(length, temp, sizeof(ULONG), &conversions2[i].buffer[pos]);
		}
	}
}