Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

cr-utils.c

Go to the documentation of this file.
00001 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
00002 
00003 /*
00004  * This file is part of The Croco Library
00005  *
00006  * Copyright (C) 2002-2003 Dodji Seketeli <dodji at seketeli.org>
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of version 2.1 of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00020  * USA
00021  */
00022 
00023 /*
00024  *$Id: cr-utils.c,v 1.9.2.1 2004/04/18 13:07:22 dodji Exp $
00025  */
00026 
00027 #include "cr-utils.h"
00028 
00029 /**
00030  *@file:
00031  *Some misc utility functions used
00032  *in the libcroco.
00033  *Note that troughout this file I will
00034  *refer to the CSS SPECIFICATIONS DOCUMENTATION
00035  *written by the w3c guys. You can find that document
00036  *at http://www.w3.org/TR/REC-CSS2/ .
00037  */
00038 
00039 /****************************
00040  *Encoding transformations and
00041  *encoding helpers
00042  ****************************/
00043 
00044 /*
00045  *Here is the correspondance between the ucs-4 charactere codes
00046  *and there matching utf-8 encoding pattern as dscribed by RFC 2279:
00047  *
00048  *UCS-4 range (hex.)    UTF-8 octet sequence (binary)
00049  *------------------    -----------------------------
00050  *0000 0000-0000 007F   0xxxxxxx
00051  *0000 0080-0000 07FF   110xxxxx 10xxxxxx
00052  *0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
00053  *0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
00054  *0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
00055  *0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx
00056  */
00057 
00058 /**
00059  *Given an utf8 string buffer, calculates
00060  *the length of this string if it was encoded
00061  *in ucs4.
00062  *@param a_in_start a pointer to the begining of
00063  *the input utf8 string.
00064  *@param a_in_end a pointre to the end of the input
00065  *utf8 string (points to the last byte of the buffer)
00066  *@param a_len out parameter the calculated length.
00067  *@return CR_OK upon succesfull completion, an error code
00068  *otherwise.
00069  */
00070 enum CRStatus
00071 cr_utils_utf8_str_len_as_ucs4 (const guchar * a_in_start,
00072                                const guchar * a_in_end, gulong * a_len)
00073 {
00074         guchar *byte_ptr = NULL;
00075         gint len = 0;
00076 
00077         /*
00078          *to store the final decoded 
00079          *unicode char
00080          */
00081         guint c = 0;
00082 
00083         g_return_val_if_fail (a_in_start && a_in_end && a_len,
00084                               CR_BAD_PARAM_ERROR);
00085         *a_len = 0;
00086 
00087         for (byte_ptr = (guchar *) a_in_start;
00088              byte_ptr <= a_in_end; byte_ptr++) {
00089                 gint nb_bytes_2_decode = 0;
00090 
00091                 if (*byte_ptr <= 0x7F) {
00092                         /*
00093                          *7 bits long char
00094                          *encoded over 1 byte:
00095                          * 0xxx xxxx
00096                          */
00097                         c = *byte_ptr;
00098                         nb_bytes_2_decode = 1;
00099 
00100                 } else if ((*byte_ptr & 0xE0) == 0xC0) {
00101                         /*
00102                          *up to 11 bits long char.
00103                          *encoded over 2 bytes:
00104                          *110x xxxx  10xx xxxx
00105                          */
00106                         c = *byte_ptr & 0x1F;
00107                         nb_bytes_2_decode = 2;
00108 
00109                 } else if ((*byte_ptr & 0xF0) == 0xE0) {
00110                         /*
00111                          *up to 16 bit long char
00112                          *encoded over 3 bytes:
00113                          *1110 xxxx  10xx xxxx  10xx xxxx
00114                          */
00115                         c = *byte_ptr & 0x0F;
00116                         nb_bytes_2_decode = 3;
00117 
00118                 } else if ((*byte_ptr & 0xF8) == 0xF0) {
00119                         /*
00120                          *up to 21 bits long char
00121                          *encoded over 4 bytes:
00122                          *1111 0xxx  10xx xxxx  10xx xxxx  10xx xxxx
00123                          */
00124                         c = *byte_ptr & 0x7;
00125                         nb_bytes_2_decode = 4;
00126 
00127                 } else if ((*byte_ptr & 0xFC) == 0xF8) {
00128                         /*
00129                          *up to 26 bits long char
00130                          *encoded over 5 bytes.
00131                          *1111 10xx  10xx xxxx  10xx xxxx  
00132                          *10xx xxxx  10xx xxxx
00133                          */
00134                         c = *byte_ptr & 3;
00135                         nb_bytes_2_decode = 5;
00136 
00137                 } else if ((*byte_ptr & 0xFE) == 0xFC) {
00138                         /*
00139                          *up to 31 bits long char
00140                          *encoded over 6 bytes:
00141                          *1111 110x  10xx xxxx  10xx xxxx  
00142                          *10xx xxxx  10xx xxxx  10xx xxxx
00143                          */
00144                         c = *byte_ptr & 1;
00145                         nb_bytes_2_decode = 6;
00146 
00147                 } else {
00148                         /*
00149                          *BAD ENCODING
00150                          */
00151                         return CR_ENCODING_ERROR;
00152                 }
00153 
00154                 /*
00155                  *Go and decode the remaining byte(s)
00156                  *(if any) to get the current character.
00157                  */
00158                 for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) {
00159                         /*decode the next byte */
00160                         byte_ptr++;
00161 
00162                         /*byte pattern must be: 10xx xxxx */
00163                         if ((*byte_ptr & 0xC0) != 0x80) {
00164                                 return CR_ENCODING_ERROR;
00165                         }
00166 
00167                         c = (c << 6) | (*byte_ptr & 0x3F);
00168                 }
00169 
00170                 len++;
00171         }
00172 
00173         *a_len = len;
00174 
00175         return CR_OK;
00176 }
00177 
00178 /**
00179  *Given an ucs4 string, this function
00180  *returns the size (in bytes) this string
00181  *would have occupied if it was encoded in utf-8.
00182  *@param a_in_start a pointer to the beginning of the input
00183  *buffer.
00184  *@param a_in_end a pointer to the end of the input buffer.
00185  *@param a_len out parameter. The computed length.
00186  *@return CR_OK upon successfull completion, an error code otherwise.
00187  */
00188 enum CRStatus
00189 cr_utils_ucs4_str_len_as_utf8 (const guint32 * a_in_start,
00190                                const guint32 * a_in_end, gulong * a_len)
00191 {
00192         gint len = 0;
00193         guint32 *char_ptr = NULL;
00194 
00195         g_return_val_if_fail (a_in_start && a_in_end && a_len,
00196                               CR_BAD_PARAM_ERROR);
00197 
00198         for (char_ptr = (guint32 *) a_in_start;
00199              char_ptr <= a_in_end; char_ptr++) {
00200                 if (*char_ptr <= 0x7F) {
00201                         /*the utf-8 char would take 1 byte */
00202                         len += 1;
00203                 } else if (*char_ptr <= 0x7FF) {
00204                         /*the utf-8 char would take 2 bytes */
00205                         len += 2;
00206                 } else if (*char_ptr <= 0xFFFF) {
00207                         len += 3;
00208                 } else if (*char_ptr <= 0x1FFFFF) {
00209                         len += 4;
00210                 } else if (*char_ptr <= 0x3FFFFFF) {
00211                         len += 5;
00212                 } else if (*char_ptr <= 0x7FFFFFFF) {
00213                         len += 6;
00214                 }
00215         }
00216 
00217         *a_len = len;
00218         return CR_OK;
00219 }
00220 
00221 /**
00222  *Given an ucsA string, this function
00223  *returns the size (in bytes) this string
00224  *would have occupied if it was encoded in utf-8.
00225  *@param a_in_start a pointer to the beginning of the input
00226  *buffer.
00227  *@param a_in_end a pointer to the end of the input buffer.
00228  *@param a_len out parameter. The computed length.
00229  *@return CR_OK upon successfull completion, an error code otherwise.
00230  */
00231 enum CRStatus
00232 cr_utils_ucs1_str_len_as_utf8 (const guchar * a_in_start,
00233                                const guchar * a_in_end, gulong * a_len)
00234 {
00235         gint len = 0;
00236         guchar *char_ptr = NULL;
00237 
00238         g_return_val_if_fail (a_in_start && a_in_end && a_len,
00239                               CR_BAD_PARAM_ERROR);
00240 
00241         for (char_ptr = (guchar *) a_in_start;
00242              char_ptr <= a_in_end; char_ptr++) {
00243                 if (*char_ptr <= 0x7F) {
00244                         /*the utf-8 char would take 1 byte */
00245                         len += 1;
00246                 } else {
00247                         /*the utf-8 char would take 2 bytes */
00248                         len += 2;
00249                 }
00250         }
00251 
00252         *a_len = len;
00253         return CR_OK;
00254 }
00255 
00256 /**
00257  *Converts an utf8 buffer into an ucs4 buffer.
00258  *
00259  *@param a_in the input utf8 buffer to convert.
00260  *@param a_in_len in/out parameter. The size of the
00261  *input buffer to convert. After return, this parameter contains
00262  *the actual number of bytes consumed.
00263  *@param a_out the output converted ucs4 buffer. Must be allocated by
00264  *the caller.
00265  *@param a_out_len in/out parameter. The size of the output buffer.
00266  *If this size is actually smaller than the real needed size, the function
00267  *just converts what it can and returns a success status. After return,
00268  *this param points to the actual number of characters decoded.
00269  *@return CR_OK upon successfull completion, an error code otherwise.
00270  */
00271 enum CRStatus
00272 cr_utils_utf8_to_ucs4 (const guchar * a_in,
00273                        gulong * a_in_len, guint32 * a_out, gulong * a_out_len)
00274 {
00275         gulong in_len = 0,
00276                 out_len = 0,
00277                 in_index = 0,
00278                 out_index = 0;
00279         enum CRStatus status = CR_OK;
00280 
00281         /*
00282          *to store the final decoded 
00283          *unicode char
00284          */
00285         guint c = 0;
00286 
00287         g_return_val_if_fail (a_in && a_in_len
00288                               && a_out && a_out_len, CR_BAD_PARAM_ERROR);
00289 
00290         if (*a_in_len < 1) {
00291                 status = CR_OK;
00292                 goto end;
00293         }
00294 
00295         in_len = *a_in_len;
00296         out_len = *a_out_len;
00297 
00298         for (in_index = 0, out_index = 0;
00299              (in_index < in_len) && (out_index < out_len);
00300              in_index++, out_index++) {
00301                 gint nb_bytes_2_decode = 0;
00302 
00303                 if (a_in[in_index] <= 0x7F) {
00304                         /*
00305                          *7 bits long char
00306                          *encoded over 1 byte:
00307                          * 0xxx xxxx
00308                          */
00309                         c = a_in[in_index];
00310                         nb_bytes_2_decode = 1;
00311 
00312                 } else if ((a_in[in_index] & 0xE0) == 0xC0) {
00313                         /*
00314                          *up to 11 bits long char.
00315                          *encoded over 2 bytes:
00316                          *110x xxxx  10xx xxxx
00317                          */
00318                         c = a_in[in_index] & 0x1F;
00319                         nb_bytes_2_decode = 2;
00320 
00321                 } else if ((a_in[in_index] & 0xF0) == 0xE0) {
00322                         /*
00323                          *up to 16 bit long char
00324                          *encoded over 3 bytes:
00325                          *1110 xxxx  10xx xxxx  10xx xxxx
00326                          */
00327                         c = a_in[in_index] & 0x0F;
00328                         nb_bytes_2_decode = 3;
00329 
00330                 } else if ((a_in[in_index] & 0xF8) == 0xF0) {
00331                         /*
00332                          *up to 21 bits long char
00333                          *encoded over 4 bytes:
00334                          *1111 0xxx  10xx xxxx  10xx xxxx  10xx xxxx
00335                          */
00336                         c = a_in[in_index] & 0x7;
00337                         nb_bytes_2_decode = 4;
00338 
00339                 } else if ((a_in[in_index] & 0xFC) == 0xF8) {
00340                         /*
00341                          *up to 26 bits long char
00342                          *encoded over 5 bytes.
00343                          *1111 10xx  10xx xxxx  10xx xxxx  
00344                          *10xx xxxx  10xx xxxx
00345                          */
00346                         c = a_in[in_index] & 3;
00347                         nb_bytes_2_decode = 5;
00348 
00349                 } else if ((a_in[in_index] & 0xFE) == 0xFC) {
00350                         /*
00351                          *up to 31 bits long char
00352                          *encoded over 6 bytes:
00353                          *1111 110x  10xx xxxx  10xx xxxx  
00354                          *10xx xxxx  10xx xxxx  10xx xxxx
00355                          */
00356                         c = a_in[in_index] & 1;
00357                         nb_bytes_2_decode = 6;
00358 
00359                 } else {
00360                         /*BAD ENCODING */
00361                         goto end;
00362                 }
00363 
00364                 /*
00365                  *Go and decode the remaining byte(s)
00366                  *(if any) to get the current character.
00367                  */
00368                 for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) {
00369                         /*decode the next byte */
00370                         in_index++;
00371 
00372                         /*byte pattern must be: 10xx xxxx */
00373                         if ((a_in[in_index] & 0xC0) != 0x80) {
00374                                 goto end;
00375                         }
00376 
00377                         c = (c << 6) | (a_in[in_index] & 0x3F);
00378                 }
00379 
00380                 /*
00381                  *The decoded ucs4 char is now
00382                  *in c.
00383                  */
00384 
00385                 /************************
00386                  *Some security tests
00387                  ***********************/
00388 
00389                 /*be sure c is a char */
00390                 if (c == 0xFFFF || c == 0xFFFE)
00391                         goto end;
00392 
00393                 /*be sure c is inferior to the max ucs4 char value */
00394                 if (c > 0x10FFFF)
00395                         goto end;
00396 
00397                 /*
00398                  *c must be less than UTF16 "lower surrogate begin"
00399                  *or higher than UTF16 "High surrogate end"
00400                  */
00401                 if (c >= 0xD800 && c <= 0xDFFF)
00402                         goto end;
00403 
00404                 /*Avoid characters that equals zero */
00405                 if (c == 0)
00406                         goto end;
00407 
00408                 a_out[out_index] = c;
00409         }
00410 
00411       end:
00412         *a_out_len = out_index + 1;
00413         *a_in_len = in_index + 1;
00414 
00415         return status;
00416 }
00417 
00418 /**
00419  *Reads a character from an utf8 buffer.
00420  *Actually decode the next character code (unicode character code)
00421  *and returns it.
00422  *@param a_in the starting address of the utf8 buffer.
00423  *@param a_in_len the length of the utf8 buffer.
00424  *@param a_out output parameter. The resulting read char.
00425  *@param a_consumed the number of the bytes consumed to
00426  *decode the returned character code.
00427  *@return CR_OK upon successfull completion, an error code otherwise.
00428  */
00429 enum CRStatus
00430 cr_utils_read_char_from_utf8_buf (const guchar * a_in,
00431                                   gulong a_in_len,
00432                                   guint32 * a_out, gulong * a_consumed)
00433 {
00434         gulong in_len = 0,
00435                 in_index = 0,
00436                 nb_bytes_2_decode = 0;
00437         enum CRStatus status = CR_OK;
00438 
00439         /*
00440          *to store the final decoded 
00441          *unicode char
00442          */
00443         guint32 c = 0;
00444 
00445         g_return_val_if_fail (a_in && a_out && a_out
00446                               && a_consumed, CR_BAD_PARAM_ERROR);
00447 
00448         if (a_in_len < 1) {
00449                 status = CR_OK;
00450                 goto end;
00451         }
00452 
00453         in_len = a_in_len;
00454 
00455         if (*a_in <= 0x7F) {
00456                 /*
00457                  *7 bits long char
00458                  *encoded over 1 byte:
00459                  * 0xxx xxxx
00460                  */
00461                 c = *a_in;
00462                 nb_bytes_2_decode = 1;
00463 
00464         } else if ((*a_in & 0xE0) == 0xC0) {
00465                 /*
00466                  *up to 11 bits long char.
00467                  *encoded over 2 bytes:
00468                  *110x xxxx  10xx xxxx
00469                  */
00470                 c = *a_in & 0x1F;
00471                 nb_bytes_2_decode = 2;
00472 
00473         } else if ((*a_in & 0xF0) == 0xE0) {
00474                 /*
00475                  *up to 16 bit long char
00476                  *encoded over 3 bytes:
00477                  *1110 xxxx  10xx xxxx  10xx xxxx
00478                  */
00479                 c = *a_in & 0x0F;
00480                 nb_bytes_2_decode = 3;
00481 
00482         } else if ((*a_in & 0xF8) == 0xF0) {
00483                 /*
00484                  *up to 21 bits long char
00485                  *encoded over 4 bytes:
00486                  *1111 0xxx  10xx xxxx  10xx xxxx  10xx xxxx
00487                  */
00488                 c = *a_in & 0x7;
00489                 nb_bytes_2_decode = 4;
00490 
00491         } else if ((*a_in & 0xFC) == 0xF8) {
00492                 /*
00493                  *up to 26 bits long char
00494                  *encoded over 5 bytes.
00495                  *1111 10xx  10xx xxxx  10xx xxxx  
00496                  *10xx xxxx  10xx xxxx
00497                  */
00498                 c = *a_in & 3;
00499                 nb_bytes_2_decode = 5;
00500 
00501         } else if ((*a_in & 0xFE) == 0xFC) {
00502                 /*
00503                  *up to 31 bits long char
00504                  *encoded over 6 bytes:
00505                  *1111 110x  10xx xxxx  10xx xxxx  
00506                  *10xx xxxx  10xx xxxx  10xx xxxx
00507                  */
00508                 c = *a_in & 1;
00509                 nb_bytes_2_decode = 6;
00510 
00511         } else {
00512                 /*BAD ENCODING */
00513                 goto end;
00514         }
00515 
00516         if (nb_bytes_2_decode > a_in_len) {
00517                 status = CR_END_OF_INPUT_ERROR;
00518                 goto end;
00519         }
00520 
00521         /*
00522          *Go and decode the remaining byte(s)
00523          *(if any) to get the current character.
00524          */
00525         for (in_index = 1; in_index < nb_bytes_2_decode; in_index++) {
00526                 /*byte pattern must be: 10xx xxxx */
00527                 if ((a_in[in_index] & 0xC0) != 0x80) {
00528                         goto end;
00529                 }
00530 
00531                 c = (c << 6) | (a_in[in_index] & 0x3F);
00532         }
00533 
00534         /*
00535          *The decoded ucs4 char is now
00536          *in c.
00537          */
00538 
00539     /************************
00540      *Some security tests
00541      ***********************/
00542 
00543         /*be sure c is a char */
00544         if (c == 0xFFFF || c == 0xFFFE)
00545                 goto end;
00546 
00547         /*be sure c is inferior to the max ucs4 char value */
00548         if (c > 0x10FFFF)
00549                 goto end;
00550 
00551         /*
00552          *c must be less than UTF16 "lower surrogate begin"
00553          *or higher than UTF16 "High surrogate end"
00554          */
00555         if (c >= 0xD800 && c <= 0xDFFF)
00556                 goto end;
00557 
00558         /*Avoid characters that equals zero */
00559         if (c == 0)
00560                 goto end;
00561 
00562         *a_out = c;
00563 
00564       end:
00565         *a_consumed = nb_bytes_2_decode;
00566 
00567         return status;
00568 }
00569 
00570 /**
00571  *
00572  */
00573 enum CRStatus
00574 cr_utils_utf8_str_len_as_ucs1 (const guchar * a_in_start,
00575                                const guchar * a_in_end, gulong * a_len)
00576 {
00577         /*
00578          *Note: this function can be made shorter
00579          *but it considers all the cases of the utf8 encoding
00580          *to ease further extensions ...
00581          */
00582 
00583         guchar *byte_ptr = NULL;
00584         gint len = 0;
00585 
00586         /*
00587          *to store the final decoded 
00588          *unicode char
00589          */
00590         guint c = 0;
00591 
00592         g_return_val_if_fail (a_in_start && a_in_end && a_len,
00593                               CR_BAD_PARAM_ERROR);
00594         *a_len = 0;
00595 
00596         for (byte_ptr = (guchar *) a_in_start;
00597              byte_ptr <= a_in_end; byte_ptr++) {
00598                 gint nb_bytes_2_decode = 0;
00599 
00600                 if (*byte_ptr <= 0x7F) {
00601                         /*
00602                          *7 bits long char
00603                          *encoded over 1 byte:
00604                          * 0xxx xxxx
00605                          */
00606                         c = *byte_ptr;
00607                         nb_bytes_2_decode = 1;
00608 
00609                 } else if ((*byte_ptr & 0xE0) == 0xC0) {
00610                         /*
00611                          *up to 11 bits long char.
00612                          *encoded over 2 bytes:
00613                          *110x xxxx  10xx xxxx
00614                          */
00615                         c = *byte_ptr & 0x1F;
00616                         nb_bytes_2_decode = 2;
00617 
00618                 } else if ((*byte_ptr & 0xF0) == 0xE0) {
00619                         /*
00620                          *up to 16 bit long char
00621                          *encoded over 3 bytes:
00622                          *1110 xxxx  10xx xxxx  10xx xxxx
00623                          */
00624                         c = *byte_ptr & 0x0F;
00625                         nb_bytes_2_decode = 3;
00626 
00627                 } else if ((*byte_ptr & 0xF8) == 0xF0) {
00628                         /*
00629                          *up to 21 bits long char
00630                          *encoded over 4 bytes:
00631                          *1111 0xxx  10xx xxxx  10xx xxxx  10xx xxxx
00632                          */
00633                         c = *byte_ptr & 0x7;
00634                         nb_bytes_2_decode = 4;
00635 
00636                 } else if ((*byte_ptr & 0xFC) == 0xF8) {
00637                         /*
00638                          *up to 26 bits long char
00639                          *encoded over 5 bytes.
00640                          *1111 10xx  10xx xxxx  10xx xxxx  
00641                          *10xx xxxx  10xx xxxx
00642                          */
00643                         c = *byte_ptr & 3;
00644                         nb_bytes_2_decode = 5;
00645 
00646                 } else if ((*byte_ptr & 0xFE) == 0xFC) {
00647                         /*
00648                          *up to 31 bits long char
00649                          *encoded over 6 bytes:
00650                          *1111 110x  10xx xxxx  10xx xxxx  
00651                          *10xx xxxx  10xx xxxx  10xx xxxx
00652                          */
00653                         c = *byte_ptr & 1;
00654                         nb_bytes_2_decode = 6;
00655 
00656                 } else {
00657                         /*
00658                          *BAD ENCODING
00659                          */
00660                         return CR_ENCODING_ERROR;
00661                 }
00662 
00663                 /*
00664                  *Go and decode the remaining byte(s)
00665                  *(if any) to get the current character.
00666                  */
00667                 for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) {
00668                         /*decode the next byte */
00669                         byte_ptr++;
00670 
00671                         /*byte pattern must be: 10xx xxxx */
00672                         if ((*byte_ptr & 0xC0) != 0x80) {
00673                                 return CR_ENCODING_ERROR;
00674                         }
00675 
00676                         c = (c << 6) | (*byte_ptr & 0x3F);
00677                 }
00678 
00679                 /*
00680                  *The decoded ucs4 char is now
00681                  *in c.
00682                  */
00683 
00684                 if (c <= 0xFF) { /*Add other conditions to support
00685                                   *other char sets (ucs2, ucs3, ucs4).
00686                                   */
00687                         len++;
00688                 } else {
00689                         /*the char is too long to fit
00690                          *into the supposed charset len.
00691                          */
00692                         return CR_ENCODING_ERROR;
00693                 }
00694         }
00695 
00696         *a_len = len;
00697 
00698         return CR_OK;
00699 }
00700 
00701 /**
00702  *Converts an utf8 string into an ucs4 string.
00703  *@param a_in the input string to convert.
00704  *@param a_in_len in/out parameter. The length of the input
00705  *string. After return, points to the actual number of bytes
00706  *consumed. This can be usefull to debug the input stream in case
00707  *of encoding error.
00708  *@param a_out out parameter. Points to the output string. It is allocated 
00709  *by this function and must be freed by the caller.
00710  *@param a_out_len out parameter. The length of the output string.
00711  *@return CR_OK upon successfull completion, an error code otherwise.
00712  *
00713  */
00714 enum CRStatus
00715 cr_utils_utf8_str_to_ucs4 (const guchar * a_in,
00716                            gulong * a_in_len,
00717                            guint32 ** a_out, gulong * a_out_len)
00718 {
00719         enum CRStatus status = CR_OK;
00720 
00721         g_return_val_if_fail (a_in && a_in_len
00722                               && a_out && a_out_len, CR_BAD_PARAM_ERROR);
00723 
00724         status = cr_utils_utf8_str_len_as_ucs4 (a_in,
00725                                                 &a_in[*a_in_len - 1],
00726                                                 a_out_len);
00727 
00728         g_return_val_if_fail (status == CR_OK, status);
00729 
00730         *a_out = g_malloc0 (*a_out_len * sizeof (guint32));
00731 
00732         status = cr_utils_utf8_to_ucs4 (a_in, a_in_len, *a_out, a_out_len);
00733 
00734         return status;
00735 }
00736 
00737 /**
00738  *Converts an ucs4 buffer into an utf8 buffer.
00739  *
00740  *@param a_in the input ucs4 buffer to convert.
00741  *@param a_in_len in/out parameter. The size of the
00742  *input buffer to convert. After return, this parameter contains
00743  *the actual number of characters consumed.
00744  *@param a_out the output converted utf8 buffer. Must be allocated by
00745  *the caller.
00746  *@param a_out_len in/out parameter. The size of the output buffer.
00747  *If this size is actually smaller than the real needed size, the function
00748  *just converts what it can and returns a success status. After return,
00749  *this param points to the actual number of bytes in the buffer.
00750  *@return CR_OK upon successfull completion, an error code otherwise.
00751  */
00752 enum CRStatus
00753 cr_utils_ucs4_to_utf8 (const guint32 * a_in,
00754                        gulong * a_in_len, guchar * a_out, gulong * a_out_len)
00755 {
00756         gulong in_len = 0,
00757                 in_index = 0,
00758                 out_index = 0;
00759         enum CRStatus status = CR_OK;
00760 
00761         g_return_val_if_fail (a_in && a_in_len && a_out && a_out_len,
00762                               CR_BAD_PARAM_ERROR);
00763 
00764         if (*a_in_len < 1) {
00765                 status = CR_OK;
00766                 goto end;
00767         }
00768 
00769         in_len = *a_in_len;
00770 
00771         for (in_index = 0; in_index < in_len; in_index++) {
00772                 /*
00773                  *FIXME: return whenever we encounter forbidden char values.
00774                  */
00775 
00776                 if (a_in[in_index] <= 0x7F) {
00777                         a_out[out_index] = a_in[in_index];
00778                         out_index++;
00779                 } else if (a_in[in_index] <= 0x7FF) {
00780                         a_out[out_index] = (0xC0 | (a_in[in_index] >> 6));
00781                         a_out[out_index + 1] =
00782                                 (0x80 | (a_in[in_index] & 0x3F));
00783                         out_index += 2;
00784                 } else if (a_in[in_index] <= 0xFFFF) {
00785                         a_out[out_index] = (0xE0 | (a_in[in_index] >> 12));
00786                         a_out[out_index + 1] =
00787                                 (0x80 | ((a_in[in_index] >> 6) & 0x3F));
00788                         a_out[out_index + 2] =
00789                                 (0x80 | (a_in[in_index] & 0x3F));
00790                         out_index += 3;
00791                 } else if (a_in[in_index] <= 0x1FFFFF) {
00792                         a_out[out_index] = (0xF0 | (a_in[in_index] >> 18));
00793                         a_out[out_index + 1]
00794                                 = (0x80 | ((a_in[in_index] >> 12) & 0x3F));
00795                         a_out[out_index + 2]
00796                                 = (0x80 | ((a_in[in_index] >> 6) & 0x3F));
00797                         a_out[out_index + 3]
00798                                 = (0x80 | (a_in[in_index] & 0x3F));
00799                         out_index += 4;
00800                 } else if (a_in[in_index] <= 0x3FFFFFF) {
00801                         a_out[out_index] = (0xF8 | (a_in[in_index] >> 24));
00802                         a_out[out_index + 1] =
00803                                 (0x80 | (a_in[in_index] >> 18));
00804                         a_out[out_index + 2]
00805                                 = (0x80 | ((a_in[in_index] >> 12) & 0x3F));
00806                         a_out[out_index + 3]
00807                                 = (0x80 | ((a_in[in_index] >> 6) & 0x3F));
00808                         a_out[out_index + 4]
00809                                 = (0x80 | (a_in[in_index] & 0x3F));
00810                         out_index += 5;
00811                 } else if (a_in[in_index] <= 0x7FFFFFFF) {
00812                         a_out[out_index] = (0xFC | (a_in[in_index] >> 30));
00813                         a_out[out_index + 1] =
00814                                 (0x80 | (a_in[in_index] >> 24));
00815                         a_out[out_index + 2]
00816                                 = (0x80 | ((a_in[in_index] >> 18) & 0x3F));
00817                         a_out[out_index + 3]
00818                                 = (0x80 | ((a_in[in_index] >> 12) & 0x3F));
00819                         a_out[out_index + 4]
00820                                 = (0x80 | ((a_in[in_index] >> 6) & 0x3F));
00821                         a_out[out_index + 4]
00822                                 = (0x80 | (a_in[in_index] & 0x3F));
00823                         out_index += 6;
00824                 } else {
00825                         status = CR_ENCODING_ERROR;
00826                         goto end;
00827                 }
00828         }                       /*end for */
00829 
00830       end:
00831         *a_in_len = in_index + 1;
00832         *a_out_len = out_index + 1;
00833 
00834         return status;
00835 }
00836 
00837 /**
00838  *Converts an ucs4 string into an utf8 string.
00839  *@param a_in the input string to convert.
00840  *@param a_in_len in/out parameter. The length of the input
00841  *string. After return, points to the actual number of characters
00842  *consumed. This can be usefull to debug the input string in case
00843  *of encoding error.
00844  *@param a_out out parameter. Points to the output string. It is allocated 
00845  *by this function and must be freed by the caller.
00846  *@param a_out_len out parameter. The length (in bytes) of the output string.
00847  *@return CR_OK upon successfull completion, an error code otherwise.
00848  */
00849 enum CRStatus
00850 cr_utils_ucs4_str_to_utf8 (const guint32 * a_in,
00851                            gulong * a_in_len,
00852                            guchar ** a_out, gulong * a_out_len)
00853 {
00854         enum CRStatus status = CR_OK;
00855 
00856         g_return_val_if_fail (a_in && a_in_len && a_out
00857                               && a_out_len, CR_BAD_PARAM_ERROR);
00858 
00859         status = cr_utils_ucs4_str_len_as_utf8 (a_in,
00860                                                 &a_in[*a_out_len - 1],
00861                                                 a_out_len);
00862 
00863         g_return_val_if_fail (status == CR_OK, status);
00864 
00865         status = cr_utils_ucs4_to_utf8 (a_in, a_in_len, *a_out, a_out_len);
00866 
00867         return status;
00868 }
00869 
00870 /**
00871  *Converts an ucs1 buffer into an utf8 buffer.
00872  *The caller must know the size of the resulting buffer and
00873  *allocate it prior to calling this function.
00874  *
00875  *@param a_in the input ucs1 buffer.
00876  *
00877  *@param a_in_len in/out parameter. The length of the input buffer.
00878  *After return, points to the number of bytes actually consumed even
00879  *in case of encoding error.
00880  *
00881  *@param a_out out parameter. The output utf8 converted buffer.
00882  *
00883  *@param a_out_len in/out parameter. The size of the output buffer.
00884  *If the output buffer size is shorter than the actual needed size, 
00885  *this function just convert what it can.
00886  *
00887  *@return CR_OK upon successfull completion, an error code otherwise.
00888  *
00889  */
00890 enum CRStatus
00891 cr_utils_ucs1_to_utf8 (const guchar * a_in,
00892                        gulong * a_in_len, guchar * a_out, gulong * a_out_len)
00893 {
00894         gulong out_index = 0,
00895                 in_index = 0,
00896                 in_len = 0,
00897                 out_len = 0;
00898         enum CRStatus status = CR_OK;
00899 
00900         g_return_val_if_fail (a_in && a_in_len
00901                               && a_out_len, 
00902                               CR_BAD_PARAM_ERROR);
00903 
00904         if (*a_in_len == 0) {
00905                 *a_out_len = 0 ;
00906                 return CR_OK ;
00907         }
00908         g_return_val_if_fail (a_out, CR_BAD_PARAM_ERROR) ;
00909 
00910         if (*a_in_len < 1) {
00911                 status = CR_OK;
00912                 goto end;
00913         }
00914 
00915         in_len = *a_in_len;
00916         out_len = *a_out_len;
00917 
00918         for (in_index = 0, out_index = 0;
00919              (in_index < in_len) && (out_index < out_len); in_index++) {
00920                 /*
00921                  *FIXME: return whenever we encounter forbidden char values.
00922                  */
00923 
00924                 if (a_in[in_index] <= 0x7F) {
00925                         a_out[out_index] = a_in[in_index];
00926                         out_index++;
00927                 } else {
00928                         a_out[out_index] = (0xC0 | (a_in[in_index] >> 6));
00929                         a_out[out_index + 1] =
00930                                 (0x80 | (a_in[in_index] & 0x3F));
00931                         out_index += 2;
00932                 }
00933         }                       /*end for */
00934 
00935       end:
00936         *a_in_len = in_index;
00937         *a_out_len = out_index;
00938 
00939         return CR_OK;
00940 }
00941 
00942 /**
00943  *Converts an ucs1 string into an utf8 string.
00944  *@param a_in_start the beginning of the input string to convert.
00945  *@param a_in_end the end of the input string to convert.
00946  *@param a_out out parameter. The converted string.
00947  *@param a_out out parameter. The length of the converted string.
00948  *@return CR_OK upon successfull completion, an error code otherwise.
00949  *
00950  */
00951 enum CRStatus
00952 cr_utils_ucs1_str_to_utf8 (const guchar * a_in,
00953                            gulong * a_in_len,
00954                            guchar ** a_out, gulong * a_out_len)
00955 {
00956         gulong in_len = 0,
00957                 out_len = 0;
00958         enum CRStatus status = CR_OK;
00959 
00960         g_return_val_if_fail (a_in && a_in_len && a_out
00961                               && a_out_len, CR_BAD_PARAM_ERROR);
00962 
00963         if (*a_in_len < 1) {
00964                 *a_out_len = 0;
00965                 *a_out = NULL;
00966                 return CR_OK;
00967         }
00968 
00969         status = cr_utils_ucs1_str_len_as_utf8 (a_in, &a_in[*a_in_len - 1],
00970                                                 &out_len);
00971 
00972         g_return_val_if_fail (status == CR_OK, status);
00973 
00974         in_len = *a_in_len;
00975 
00976         *a_out = g_malloc0 (out_len);
00977 
00978         status = cr_utils_ucs1_to_utf8 (a_in, a_in_len, *a_out, &out_len);
00979 
00980         *a_out_len = out_len;
00981 
00982         return status;
00983 }
00984 
00985 /**
00986  *Converts an utf8 buffer into an ucs1 buffer.
00987  *The caller must know the size of the resulting
00988  *converted buffer, and allocated it prior to calling this
00989  *function.
00990  *
00991  *@param a_in the input utf8 buffer to convert.
00992  *
00993  *@param a_in_len in/out parameter. The size of the input utf8 buffer.
00994  *After return, points to the number of bytes consumed
00995  *by the function even in case of encoding error.
00996  *
00997  *@param a_out out parameter. Points to the resulting buffer.
00998  *Must be allocated by the caller. If the size of a_out is shorter
00999  *than its required size, this function converts what it can and return
01000  *a successfull status.
01001  *
01002  *@param a_out_len in/out parameter. The size of the output buffer.
01003  *After return, points to the number of bytes consumed even in case of
01004  *encoding error.
01005  *
01006  *@return CR_OK upon successfull completion, an error code otherwise.
01007  */
01008 enum CRStatus
01009 cr_utils_utf8_to_ucs1 (const guchar * a_in,
01010                        gulong * a_in_len, guchar * a_out, gulong * a_out_len)
01011 {
01012         gulong in_index = 0,
01013                 out_index = 0,
01014                 in_len = 0,
01015                 out_len = 0;
01016         enum CRStatus status = CR_OK;
01017 
01018         /*
01019          *to store the final decoded 
01020          *unicode char
01021          */
01022         guint32 c = 0;
01023 
01024         g_return_val_if_fail (a_in && a_in_len
01025                               && a_out && a_out_len, CR_BAD_PARAM_ERROR);
01026 
01027         if (*a_in_len < 1) {
01028                 status = CR_OK;
01029                 goto end;
01030         }
01031 
01032         in_len = *a_in_len;
01033         out_len = *a_out_len;
01034 
01035         for (in_index = 0, out_index = 0;
01036              (in_index < in_len) && (out_index < out_len);
01037              in_index++, out_index++) {
01038                 gint nb_bytes_2_decode = 0;
01039 
01040                 if (a_in[in_index] <= 0x7F) {
01041                         /*
01042                          *7 bits long char
01043                          *encoded over 1 byte:
01044                          * 0xxx xxxx
01045                          */
01046                         c = a_in[in_index];
01047                         nb_bytes_2_decode = 1;
01048 
01049                 } else if ((a_in[in_index] & 0xE0) == 0xC0) {
01050                         /*
01051                          *up to 11 bits long char.
01052                          *encoded over 2 bytes:
01053                          *110x xxxx  10xx xxxx
01054                          */
01055                         c = a_in[in_index] & 0x1F;
01056                         nb_bytes_2_decode = 2;
01057 
01058                 } else if ((a_in[in_index] & 0xF0) == 0xE0) {
01059                         /*
01060                          *up to 16 bit long char
01061                          *encoded over 3 bytes:
01062                          *1110 xxxx  10xx xxxx  10xx xxxx
01063                          */
01064                         c = a_in[in_index] & 0x0F;
01065                         nb_bytes_2_decode = 3;
01066 
01067                 } else if ((a_in[in_index] & 0xF8) == 0xF0) {
01068                         /*
01069                          *up to 21 bits long char
01070                          *encoded over 4 bytes:
01071                          *1111 0xxx  10xx xxxx  10xx xxxx  10xx xxxx
01072                          */
01073                         c = a_in[in_index] & 0x7;
01074                         nb_bytes_2_decode = 4;
01075 
01076                 } else if ((a_in[in_index] & 0xFC) == 0xF8) {
01077                         /*
01078                          *up to 26 bits long char
01079                          *encoded over 5 bytes.
01080                          *1111 10xx  10xx xxxx  10xx xxxx  
01081                          *10xx xxxx  10xx xxxx
01082                          */
01083                         c = a_in[in_index] & 3;
01084                         nb_bytes_2_decode = 5;
01085 
01086                 } else if ((a_in[in_index] & 0xFE) == 0xFC) {
01087                         /*
01088                          *up to 31 bits long char
01089                          *encoded over 6 bytes:
01090                          *1111 110x  10xx xxxx  10xx xxxx  
01091                          *10xx xxxx  10xx xxxx  10xx xxxx
01092                          */
01093                         c = a_in[in_index] & 1;
01094                         nb_bytes_2_decode = 6;
01095 
01096                 } else {
01097                         /*BAD ENCODING */
01098                         status = CR_ENCODING_ERROR;
01099                         goto end;
01100                 }
01101 
01102                 /*
01103                  *Go and decode the remaining byte(s)
01104                  *(if any) to get the current character.
01105                  */
01106                 if (in_index + nb_bytes_2_decode - 1 >= in_len) {
01107                         status = CR_OK;
01108                         goto end;
01109                 }
01110 
01111                 for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) {
01112                         /*decode the next byte */
01113                         in_index++;
01114 
01115                         /*byte pattern must be: 10xx xxxx */
01116                         if ((a_in[in_index] & 0xC0) != 0x80) {
01117                                 status = CR_ENCODING_ERROR;
01118                                 goto end;
01119                         }
01120 
01121                         c = (c << 6) | (a_in[in_index] & 0x3F);
01122                 }
01123 
01124                 /*
01125                  *The decoded ucs4 char is now
01126                  *in c.
01127                  */
01128 
01129                 if (c > 0xFF) {
01130                         status = CR_ENCODING_ERROR;
01131                         goto end;
01132                 }
01133 
01134                 a_out[out_index] = c;
01135         }
01136 
01137       end:
01138         *a_out_len = out_index;
01139         *a_in_len = in_index;
01140 
01141         return CR_OK;
01142 }
01143 
01144 /**
01145  *Converts an utf8 buffer into an
01146  *ucs1 buffer.
01147  *@param a_in_start the start of the input buffer.
01148  *@param a_in_end the end of the input buffer.
01149  *@param a_out out parameter. The resulting converted ucs4 buffer.
01150  *Must be freed by the caller.
01151  *@param a_out_len out parameter. The length of the converted buffer.
01152  *@return CR_OK upon successfull completion, an error code otherwise.
01153  *Note that out parameters are valid if and only if this function
01154  *returns CR_OK.
01155  */
01156 enum CRStatus
01157 cr_utils_utf8_str_to_ucs1 (const guchar * a_in,
01158                            gulong * a_in_len,
01159                            guchar ** a_out, gulong * a_out_len)
01160 {
01161         enum CRStatus status = CR_OK;
01162 
01163         g_return_val_if_fail (a_in && a_in_len
01164                               && a_out && a_out_len, CR_BAD_PARAM_ERROR);
01165 
01166         if (*a_in_len < 1) {
01167                 *a_out_len = 0;
01168                 *a_out = NULL;
01169                 return CR_OK;
01170         }
01171 
01172         status = cr_utils_utf8_str_len_as_ucs4 (a_in, &a_in[*a_in_len - 1],
01173                                                 a_out_len);
01174 
01175         g_return_val_if_fail (status == CR_OK, status);
01176 
01177         *a_out = g_malloc0 (*a_out_len * sizeof (guint32));
01178 
01179         status = cr_utils_utf8_to_ucs1 (a_in, a_in_len, *a_out, a_out_len);
01180         return status;
01181 }
01182 
01183 /*****************************************
01184  *CSS basic types identification utilities
01185  *****************************************/
01186 
01187 /**
01188  *Returns TRUE if a_char is a white space as
01189  *defined in the css spec in chap 4.1.1.
01190  *
01191  *white-space ::= ' '| \t|\r|\n|\f
01192  *
01193  *@param a_char the character to test.
01194  *return TRUE if is a white space, false otherwise.
01195  */
01196 gboolean
01197 cr_utils_is_white_space (guint32 a_char)
01198 {
01199         switch (a_char) {
01200         case ' ':
01201         case '\t':
01202         case '\r':
01203         case '\n':
01204         case '\f':
01205                 return TRUE;
01206                 break;
01207         default:
01208                 return FALSE;
01209         }
01210 }
01211 
01212 /**
01213  *Returns true if the character is a newline
01214  *as defined in the css spec in the chap 4.1.1.
01215  *
01216  *nl ::= \n|\r\n|\r|\f
01217  *
01218  *@param a_char the character to test.
01219  *@return TRUE if the character is a newline, FALSE otherwise.
01220  */
01221 gboolean
01222 cr_utils_is_newline (guint32 a_char)
01223 {
01224         switch (a_char) {
01225         case '\n':
01226         case '\r':
01227         case '\f':
01228                 return TRUE;
01229                 break;
01230         default:
01231                 return FALSE;
01232         }
01233 }
01234 
01235 /**
01236  *returns TRUE if the char is part of an hexa num char:
01237  *i.e hexa_char ::= [0-9A-F]
01238  */
01239 gboolean
01240 cr_utils_is_hexa_char (guint32 a_char)
01241 {
01242         if ((a_char >= '0' && a_char <= '9')
01243             || (a_char >= 'A' && a_char <= 'F')) {
01244                 return TRUE;
01245         }
01246         return FALSE;
01247 }
01248 
01249 /**
01250  *Returns true if the character is a nonascii
01251  *character (as defined in the css spec chap 4.1.1):
01252  *
01253  *nonascii ::= [^\0-\177]
01254  *
01255  *@param a_char the character to test.
01256  *@return TRUE if the character is a nonascii char,
01257  *FALSE otherwise.
01258  */
01259 gboolean
01260 cr_utils_is_nonascii (guint32 a_char)
01261 {
01262         if (a_char <= 177) {
01263                 return FALSE;
01264         }
01265 
01266         return TRUE;
01267 }
01268 
01269 /**
01270  *Dumps a character a_nb times on a file.
01271  *@param a_char the char to dump
01272  *@param a_fp the destination file pointer
01273  *@param a_nb the number of times a_char is to be dumped.
01274  */
01275 void
01276 cr_utils_dump_n_chars (guchar a_char, FILE * a_fp, glong a_nb)
01277 {
01278         glong i = 0;
01279 
01280         for (i = 0; i < a_nb; i++) {
01281                 fprintf (a_fp, "%c", a_char);
01282         }
01283 }
01284 
01285 void
01286 cr_utils_dump_n_chars2 (guchar a_char, GString * a_string, glong a_nb)
01287 {
01288         glong i = 0;
01289 
01290         g_return_if_fail (a_string);
01291 
01292         for (i = 0; i < a_nb; i++) {
01293                 g_string_append_printf (a_string, "%c", a_char);
01294         }
01295 }
01296 
01297 gdouble
01298 cr_utils_n_to_0_dot_n (glong a_n)
01299 {
01300         gdouble result = a_n;
01301 
01302         while (ABS (result) > 1) {
01303                 result = result / 10;
01304         }
01305 
01306         return result;
01307 }
01308 
01309 /**
01310  *Duplicates a list of GString instances.
01311  *@return the duplicated list of GString instances or NULL if
01312  *something bad happened.
01313  *@param a_list_of_strings the list of strings to be duplicated.
01314  */
01315 GList *
01316 cr_dup_glist_of_string (GList * a_list_of_strings)
01317 {
01318         GList *cur = NULL,
01319                 *result = NULL;
01320 
01321         g_return_val_if_fail (a_list_of_strings, NULL);
01322 
01323         for (cur = a_list_of_strings; cur; cur = cur->next) {
01324                 GString *str = NULL;
01325 
01326                 str = g_string_new_len (((GString *) cur->data)->str,
01327                                         ((GString *) cur->data)->len);
01328                 if (str)
01329                         result = g_list_append (result, str);
01330         }
01331 
01332         return result;
01333 }

Generated on Tue Apr 27 13:46:36 2004 for Libcroco by doxygen 1.3.6