1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971 |
- /*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2016 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Rui Hirokawa <rui_hirokawa@ybb.ne.jp> |
- | Stig Bakken <ssb@php.net> |
- | Moriyoshi Koizumi <moriyoshi@php.net> |
- +----------------------------------------------------------------------+
- */
- /* $Id$ */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include "php.h"
- #include "php_globals.h"
- #include "ext/standard/info.h"
- #include "main/php_output.h"
- #include "SAPI.h"
- #include "php_ini.h"
- #ifdef HAVE_STDLIB_H
- # include <stdlib.h>
- #endif
- #include <errno.h>
- #include "php_iconv.h"
- #ifdef HAVE_ICONV
- #ifdef PHP_ICONV_H_PATH
- #include PHP_ICONV_H_PATH
- #else
- #include <iconv.h>
- #endif
- #ifdef HAVE_GLIBC_ICONV
- #include <gnu/libc-version.h>
- #endif
- #ifdef HAVE_LIBICONV
- #undef iconv
- #endif
- #include "ext/standard/php_smart_str.h"
- #include "ext/standard/base64.h"
- #include "ext/standard/quot_print.h"
- #define _php_iconv_memequal(a, b, c) \
- ((c) == sizeof(unsigned long) ? *((unsigned long *)(a)) == *((unsigned long *)(b)) : ((c) == sizeof(unsigned int) ? *((unsigned int *)(a)) == *((unsigned int *)(b)) : memcmp(a, b, c) == 0))
- /* {{{ arginfo */
- ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_strlen, 0, 0, 1)
- ZEND_ARG_INFO(0, str)
- ZEND_ARG_INFO(0, charset)
- ZEND_END_ARG_INFO()
- ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_substr, 0, 0, 2)
- ZEND_ARG_INFO(0, str)
- ZEND_ARG_INFO(0, offset)
- ZEND_ARG_INFO(0, length)
- ZEND_ARG_INFO(0, charset)
- ZEND_END_ARG_INFO()
- ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_strpos, 0, 0, 2)
- ZEND_ARG_INFO(0, haystack)
- ZEND_ARG_INFO(0, needle)
- ZEND_ARG_INFO(0, offset)
- ZEND_ARG_INFO(0, charset)
- ZEND_END_ARG_INFO()
- ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_strrpos, 0, 0, 2)
- ZEND_ARG_INFO(0, haystack)
- ZEND_ARG_INFO(0, needle)
- ZEND_ARG_INFO(0, charset)
- ZEND_END_ARG_INFO()
- ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_mime_encode, 0, 0, 2)
- ZEND_ARG_INFO(0, field_name)
- ZEND_ARG_INFO(0, field_value)
- ZEND_ARG_INFO(0, preference) /* ZEND_ARG_ARRAY_INFO(0, preference, 1) */
- ZEND_END_ARG_INFO()
- ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_mime_decode, 0, 0, 1)
- ZEND_ARG_INFO(0, encoded_string)
- ZEND_ARG_INFO(0, mode)
- ZEND_ARG_INFO(0, charset)
- ZEND_END_ARG_INFO()
- ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_mime_decode_headers, 0, 0, 1)
- ZEND_ARG_INFO(0, headers)
- ZEND_ARG_INFO(0, mode)
- ZEND_ARG_INFO(0, charset)
- ZEND_END_ARG_INFO()
- ZEND_BEGIN_ARG_INFO(arginfo_iconv, 0)
- ZEND_ARG_INFO(0, in_charset)
- ZEND_ARG_INFO(0, out_charset)
- ZEND_ARG_INFO(0, str)
- ZEND_END_ARG_INFO()
- ZEND_BEGIN_ARG_INFO(arginfo_iconv_set_encoding, 0)
- ZEND_ARG_INFO(0, type)
- ZEND_ARG_INFO(0, charset)
- ZEND_END_ARG_INFO()
- ZEND_BEGIN_ARG_INFO_EX(arginfo_iconv_get_encoding, 0, 0, 0)
- ZEND_ARG_INFO(0, type)
- ZEND_END_ARG_INFO()
- /* }}} */
- /* {{{ iconv_functions[]
- */
- const zend_function_entry iconv_functions[] = {
- PHP_RAW_NAMED_FE(iconv,php_if_iconv, arginfo_iconv)
- PHP_FE(iconv_get_encoding, arginfo_iconv_get_encoding)
- PHP_FE(iconv_set_encoding, arginfo_iconv_set_encoding)
- PHP_FE(iconv_strlen, arginfo_iconv_strlen)
- PHP_FE(iconv_substr, arginfo_iconv_substr)
- PHP_FE(iconv_strpos, arginfo_iconv_strpos)
- PHP_FE(iconv_strrpos, arginfo_iconv_strrpos)
- PHP_FE(iconv_mime_encode, arginfo_iconv_mime_encode)
- PHP_FE(iconv_mime_decode, arginfo_iconv_mime_decode)
- PHP_FE(iconv_mime_decode_headers, arginfo_iconv_mime_decode_headers)
- PHP_FE_END
- };
- /* }}} */
- ZEND_DECLARE_MODULE_GLOBALS(iconv)
- static PHP_GINIT_FUNCTION(iconv);
- /* {{{ iconv_module_entry
- */
- zend_module_entry iconv_module_entry = {
- STANDARD_MODULE_HEADER,
- "iconv",
- iconv_functions,
- PHP_MINIT(miconv),
- PHP_MSHUTDOWN(miconv),
- NULL,
- NULL,
- PHP_MINFO(miconv),
- NO_VERSION_YET,
- PHP_MODULE_GLOBALS(iconv),
- PHP_GINIT(iconv),
- NULL,
- NULL,
- STANDARD_MODULE_PROPERTIES_EX
- };
- /* }}} */
- #ifdef COMPILE_DL_ICONV
- ZEND_GET_MODULE(iconv)
- #endif
- /* {{{ PHP_GINIT_FUNCTION */
- static PHP_GINIT_FUNCTION(iconv)
- {
- iconv_globals->input_encoding = NULL;
- iconv_globals->output_encoding = NULL;
- iconv_globals->internal_encoding = NULL;
- }
- /* }}} */
- #if defined(HAVE_LIBICONV) && defined(ICONV_ALIASED_LIBICONV)
- #define iconv libiconv
- #endif
- /* {{{ typedef enum php_iconv_enc_scheme_t */
- typedef enum _php_iconv_enc_scheme_t {
- PHP_ICONV_ENC_SCHEME_BASE64,
- PHP_ICONV_ENC_SCHEME_QPRINT
- } php_iconv_enc_scheme_t;
- /* }}} */
- #define PHP_ICONV_MIME_DECODE_STRICT (1<<0)
- #define PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR (1<<1)
- /* {{{ prototypes */
- static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, iconv_t cd);
- static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd);
- static void _php_iconv_show_error(php_iconv_err_t err, const char *out_charset, const char *in_charset TSRMLS_DC);
- static php_iconv_err_t _php_iconv_strlen(unsigned int *pretval, const char *str, size_t nbytes, const char *enc);
- static php_iconv_err_t _php_iconv_substr(smart_str *pretval, const char *str, size_t nbytes, int offset, int len, const char *enc);
- static php_iconv_err_t _php_iconv_strpos(unsigned int *pretval, const char *haystk, size_t haystk_nbytes, const char *ndl, size_t ndl_nbytes, int offset, const char *enc);
- static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fname, size_t fname_nbytes, const char *fval, size_t fval_nbytes, unsigned int max_line_len, const char *lfchars, php_iconv_enc_scheme_t enc_scheme, const char *out_charset, const char *enc);
- static php_iconv_err_t _php_iconv_mime_decode(smart_str *pretval, const char *str, size_t str_nbytes, const char *enc, const char **next_pos, int mode);
- static php_iconv_err_t php_iconv_stream_filter_register_factory(TSRMLS_D);
- static php_iconv_err_t php_iconv_stream_filter_unregister_factory(TSRMLS_D);
- static int php_iconv_output_conflict(const char *handler_name, size_t handler_name_len TSRMLS_DC);
- static php_output_handler *php_iconv_output_handler_init(const char *name, size_t name_len, size_t chunk_size, int flags TSRMLS_DC);
- static int php_iconv_output_handler(void **nothing, php_output_context *output_context);
- /* }}} */
- /* {{{ static globals */
- static char _generic_superset_name[] = ICONV_UCS4_ENCODING;
- #define GENERIC_SUPERSET_NAME _generic_superset_name
- #define GENERIC_SUPERSET_NBYTES 4
- /* }}} */
- static PHP_INI_MH(OnUpdateInputEncoding)
- {
- if (new_value_length >= ICONV_CSNMAXLEN) {
- return FAILURE;
- }
- if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
- php_error_docref("ref.iconv" TSRMLS_CC, E_DEPRECATED, "Use of iconv.input_encoding is deprecated");
- }
- OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
- return SUCCESS;
- }
- static PHP_INI_MH(OnUpdateOutputEncoding)
- {
- if(new_value_length >= ICONV_CSNMAXLEN) {
- return FAILURE;
- }
- if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
- php_error_docref("ref.iconv" TSRMLS_CC, E_DEPRECATED, "Use of iconv.output_encoding is deprecated");
- }
- OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
- return SUCCESS;
- }
- static PHP_INI_MH(OnUpdateInternalEncoding)
- {
- if(new_value_length >= ICONV_CSNMAXLEN) {
- return FAILURE;
- }
- if (stage & (PHP_INI_STAGE_ACTIVATE | PHP_INI_STAGE_RUNTIME)) {
- php_error_docref("ref.iconv" TSRMLS_CC, E_DEPRECATED, "Use of iconv.internal_encoding is deprecated");
- }
- OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
- return SUCCESS;
- }
- /* {{{ PHP_INI
- */
- PHP_INI_BEGIN()
- STD_PHP_INI_ENTRY("iconv.input_encoding", "", PHP_INI_ALL, OnUpdateInputEncoding, input_encoding, zend_iconv_globals, iconv_globals)
- STD_PHP_INI_ENTRY("iconv.output_encoding", "", PHP_INI_ALL, OnUpdateOutputEncoding, output_encoding, zend_iconv_globals, iconv_globals)
- STD_PHP_INI_ENTRY("iconv.internal_encoding", "", PHP_INI_ALL, OnUpdateInternalEncoding, internal_encoding, zend_iconv_globals, iconv_globals)
- PHP_INI_END()
- /* }}} */
- /* {{{ PHP_MINIT_FUNCTION */
- PHP_MINIT_FUNCTION(miconv)
- {
- char *version = "unknown";
- REGISTER_INI_ENTRIES();
- #if HAVE_LIBICONV
- {
- static char buf[16];
- snprintf(buf, sizeof(buf), "%d.%d",
- ((_libiconv_version >> 8) & 0x0f), (_libiconv_version & 0x0f));
- version = buf;
- }
- #elif HAVE_GLIBC_ICONV
- version = (char *)gnu_get_libc_version();
- #elif defined(NETWARE)
- version = "OS built-in";
- #endif
- #ifdef PHP_ICONV_IMPL
- REGISTER_STRING_CONSTANT("ICONV_IMPL", PHP_ICONV_IMPL, CONST_CS | CONST_PERSISTENT);
- #elif HAVE_LIBICONV
- REGISTER_STRING_CONSTANT("ICONV_IMPL", "libiconv", CONST_CS | CONST_PERSISTENT);
- #elif defined(NETWARE)
- REGISTER_STRING_CONSTANT("ICONV_IMPL", "Novell", CONST_CS | CONST_PERSISTENT);
- #else
- REGISTER_STRING_CONSTANT("ICONV_IMPL", "unknown", CONST_CS | CONST_PERSISTENT);
- #endif
- REGISTER_STRING_CONSTANT("ICONV_VERSION", version, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("ICONV_MIME_DECODE_STRICT", PHP_ICONV_MIME_DECODE_STRICT, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("ICONV_MIME_DECODE_CONTINUE_ON_ERROR", PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR, CONST_CS | CONST_PERSISTENT);
- if (php_iconv_stream_filter_register_factory(TSRMLS_C) != PHP_ICONV_ERR_SUCCESS) {
- return FAILURE;
- }
- php_output_handler_alias_register(ZEND_STRL("ob_iconv_handler"), php_iconv_output_handler_init TSRMLS_CC);
- php_output_handler_conflict_register(ZEND_STRL("ob_iconv_handler"), php_iconv_output_conflict TSRMLS_CC);
- return SUCCESS;
- }
- /* }}} */
- /* {{{ PHP_MSHUTDOWN_FUNCTION */
- PHP_MSHUTDOWN_FUNCTION(miconv)
- {
- php_iconv_stream_filter_unregister_factory(TSRMLS_C);
- UNREGISTER_INI_ENTRIES();
- return SUCCESS;
- }
- /* }}} */
- /* {{{ PHP_MINFO_FUNCTION */
- PHP_MINFO_FUNCTION(miconv)
- {
- zval iconv_impl, iconv_ver;
- zend_get_constant("ICONV_IMPL", sizeof("ICONV_IMPL")-1, &iconv_impl TSRMLS_CC);
- zend_get_constant("ICONV_VERSION", sizeof("ICONV_VERSION")-1, &iconv_ver TSRMLS_CC);
- php_info_print_table_start();
- php_info_print_table_row(2, "iconv support", "enabled");
- php_info_print_table_row(2, "iconv implementation", Z_STRVAL(iconv_impl));
- php_info_print_table_row(2, "iconv library version", Z_STRVAL(iconv_ver));
- php_info_print_table_end();
- DISPLAY_INI_ENTRIES();
- zval_dtor(&iconv_impl);
- zval_dtor(&iconv_ver);
- }
- /* }}} */
- static char *get_internal_encoding(TSRMLS_D) {
- if (ICONVG(internal_encoding) && ICONVG(internal_encoding)[0]) {
- return ICONVG(internal_encoding);
- } else if (PG(internal_encoding) && PG(internal_encoding)[0]) {
- return PG(internal_encoding);
- } else if (SG(default_charset)) {
- return SG(default_charset);
- }
- return "";
- }
- static char *get_input_encoding(TSRMLS_D) {
- if (ICONVG(input_encoding) && ICONVG(input_encoding)[0]) {
- return ICONVG(input_encoding);
- } else if (PG(input_encoding) && PG(input_encoding)[0]) {
- return PG(input_encoding);
- } else if (SG(default_charset)) {
- return SG(default_charset);
- }
- return "";
- }
- static char *get_output_encoding(TSRMLS_D) {
- if (ICONVG(output_encoding) && ICONVG(output_encoding)[0]) {
- return ICONVG(output_encoding);
- } else if (PG(output_encoding) && PG(output_encoding)[0]) {
- return PG(output_encoding);
- } else if (SG(default_charset)) {
- return SG(default_charset);
- }
- return "";
- }
- static int php_iconv_output_conflict(const char *handler_name, size_t handler_name_len TSRMLS_DC)
- {
- if (php_output_get_level(TSRMLS_C)) {
- if (php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("ob_iconv_handler") TSRMLS_CC)
- || php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("mb_output_handler") TSRMLS_CC)) {
- return FAILURE;
- }
- }
- return SUCCESS;
- }
- static php_output_handler *php_iconv_output_handler_init(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags TSRMLS_DC)
- {
- return php_output_handler_create_internal(handler_name, handler_name_len, php_iconv_output_handler, chunk_size, flags TSRMLS_CC);
- }
- static int php_iconv_output_handler(void **nothing, php_output_context *output_context)
- {
- char *s, *content_type, *mimetype = NULL;
- int output_status, mimetype_len = 0;
- PHP_OUTPUT_TSRMLS(output_context);
- if (output_context->op & PHP_OUTPUT_HANDLER_START) {
- output_status = php_output_get_status(TSRMLS_C);
- if (output_status & PHP_OUTPUT_SENT) {
- return FAILURE;
- }
- if (SG(sapi_headers).mimetype && !strncasecmp(SG(sapi_headers).mimetype, "text/", 5)) {
- if ((s = strchr(SG(sapi_headers).mimetype,';')) == NULL){
- mimetype = SG(sapi_headers).mimetype;
- } else {
- mimetype = SG(sapi_headers).mimetype;
- mimetype_len = s - SG(sapi_headers).mimetype;
- }
- } else if (SG(sapi_headers).send_default_content_type) {
- mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE;
- }
- if (mimetype != NULL && !(output_context->op & PHP_OUTPUT_HANDLER_CLEAN)) {
- int len;
- char *p = strstr(get_output_encoding(TSRMLS_C), "//");
- if (p) {
- len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%.*s", mimetype_len ? mimetype_len : (int) strlen(mimetype), mimetype, (int)(p - get_output_encoding(TSRMLS_C)), get_output_encoding(TSRMLS_C));
- } else {
- len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%s", mimetype_len ? mimetype_len : (int) strlen(mimetype), mimetype, get_output_encoding(TSRMLS_C));
- }
- if (content_type && SUCCESS == sapi_add_header(content_type, len, 0)) {
- SG(sapi_headers).send_default_content_type = 0;
- php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL TSRMLS_CC);
- }
- }
- }
- if (output_context->in.used) {
- output_context->out.free = 1;
- _php_iconv_show_error(php_iconv_string(output_context->in.data, output_context->in.used, &output_context->out.data, &output_context->out.used, get_output_encoding(TSRMLS_C), get_internal_encoding(TSRMLS_C)), get_output_encoding(TSRMLS_C), get_internal_encoding(TSRMLS_C) TSRMLS_CC);
- }
- return SUCCESS;
- }
- /* {{{ _php_iconv_appendl() */
- static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, iconv_t cd)
- {
- const char *in_p = s;
- size_t in_left = l;
- char *out_p;
- size_t out_left = 0;
- size_t buf_growth = 128;
- #if !ICONV_SUPPORTS_ERRNO
- size_t prev_in_left = in_left;
- #endif
- if (in_p != NULL) {
- while (in_left > 0) {
- out_left = buf_growth - out_left;
- {
- size_t newlen;
- smart_str_alloc((d), out_left, 0);
- }
- out_p = (d)->c + (d)->len;
- if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
- #if ICONV_SUPPORTS_ERRNO
- switch (errno) {
- case EINVAL:
- return PHP_ICONV_ERR_ILLEGAL_CHAR;
- case EILSEQ:
- return PHP_ICONV_ERR_ILLEGAL_SEQ;
- case E2BIG:
- break;
- default:
- return PHP_ICONV_ERR_UNKNOWN;
- }
- #else
- if (prev_in_left == in_left) {
- return PHP_ICONV_ERR_UNKNOWN;
- }
- #endif
- }
- #if !ICONV_SUPPORTS_ERRNO
- prev_in_left = in_left;
- #endif
- (d)->len += (buf_growth - out_left);
- buf_growth <<= 1;
- }
- } else {
- for (;;) {
- out_left = buf_growth - out_left;
- {
- size_t newlen;
- smart_str_alloc((d), out_left, 0);
- }
- out_p = (d)->c + (d)->len;
- if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)0) {
- (d)->len += (buf_growth - out_left);
- break;
- } else {
- #if ICONV_SUPPORTS_ERRNO
- if (errno != E2BIG) {
- return PHP_ICONV_ERR_UNKNOWN;
- }
- #else
- if (out_left != 0) {
- return PHP_ICONV_ERR_UNKNOWN;
- }
- #endif
- }
- (d)->len += (buf_growth - out_left);
- buf_growth <<= 1;
- }
- }
- return PHP_ICONV_ERR_SUCCESS;
- }
- /* }}} */
- /* {{{ _php_iconv_appendc() */
- static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd)
- {
- return _php_iconv_appendl(d, &c, 1, cd);
- }
- /* }}} */
- /* {{{ */
- #if ICONV_BROKEN_IGNORE
- static int _php_check_ignore(const char *charset)
- {
- size_t clen = strlen(charset);
- if (clen >= 9 && strcmp("//IGNORE", charset+clen-8) == 0) {
- return 1;
- }
- if (clen >= 19 && strcmp("//IGNORE//TRANSLIT", charset+clen-18) == 0) {
- return 1;
- }
- return 0;
- }
- #else
- #define _php_check_ignore(x) (0)
- #endif
- /* }}} */
- /* {{{ php_iconv_string()
- */
- PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
- char **out, size_t *out_len,
- const char *out_charset, const char *in_charset)
- {
- #if !ICONV_SUPPORTS_ERRNO
- size_t in_size, out_size, out_left;
- char *out_buffer, *out_p;
- iconv_t cd;
- size_t result;
- *out = NULL;
- *out_len = 0;
- /*
- This is not the right way to get output size...
- This is not space efficient for large text.
- This is also problem for encoding like UTF-7/UTF-8/ISO-2022 which
- a single char can be more than 4 bytes.
- I added 15 extra bytes for safety. <yohgaki@php.net>
- */
- out_size = in_len * sizeof(int) + 15;
- out_left = out_size;
- in_size = in_len;
- cd = iconv_open(out_charset, in_charset);
- if (cd == (iconv_t)(-1)) {
- return PHP_ICONV_ERR_UNKNOWN;
- }
- out_buffer = (char *) emalloc(out_size + 1);
- out_p = out_buffer;
- #ifdef NETWARE
- result = iconv(cd, (char **) &in_p, &in_size, (char **)
- #else
- result = iconv(cd, (const char **) &in_p, &in_size, (char **)
- #endif
- &out_p, &out_left);
- if (result == (size_t)(-1)) {
- efree(out_buffer);
- return PHP_ICONV_ERR_UNKNOWN;
- }
- if (out_left < 8) {
- size_t pos = out_p - out_buffer;
- out_buffer = (char *) safe_erealloc(out_buffer, out_size, 1, 8);
- out_p = out_buffer+pos;
- out_size += 7;
- out_left += 7;
- }
- /* flush the shift-out sequences */
- result = iconv(cd, NULL, NULL, &out_p, &out_left);
- if (result == (size_t)(-1)) {
- efree(out_buffer);
- return PHP_ICONV_ERR_UNKNOWN;
- }
- *out_len = out_size - out_left;
- out_buffer[*out_len] = '\0';
- *out = out_buffer;
- iconv_close(cd);
- return PHP_ICONV_ERR_SUCCESS;
- #else
- /*
- iconv supports errno. Handle it better way.
- */
- iconv_t cd;
- size_t in_left, out_size, out_left;
- char *out_p, *out_buf, *tmp_buf;
- size_t bsz, result = 0;
- php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS;
- int ignore_ilseq = _php_check_ignore(out_charset);
- *out = NULL;
- *out_len = 0;
- cd = iconv_open(out_charset, in_charset);
- if (cd == (iconv_t)(-1)) {
- if (errno == EINVAL) {
- return PHP_ICONV_ERR_WRONG_CHARSET;
- } else {
- return PHP_ICONV_ERR_CONVERTER;
- }
- }
- in_left= in_len;
- out_left = in_len + 32; /* Avoid realloc() most cases */
- out_size = 0;
- bsz = out_left;
- out_buf = (char *) emalloc(bsz+1);
- out_p = out_buf;
- while (in_left > 0) {
- result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
- out_size = bsz - out_left;
- if (result == (size_t)(-1)) {
- if (ignore_ilseq && errno == EILSEQ) {
- if (in_left <= 1) {
- result = 0;
- } else {
- errno = 0;
- in_p++;
- in_left--;
- continue;
- }
- }
- if (errno == E2BIG && in_left > 0) {
- /* converted string is longer than out buffer */
- bsz += in_len;
- tmp_buf = (char*) erealloc(out_buf, bsz+1);
- out_p = out_buf = tmp_buf;
- out_p += out_size;
- out_left = bsz - out_size;
- continue;
- }
- }
- break;
- }
- if (result != (size_t)(-1)) {
- /* flush the shift-out sequences */
- for (;;) {
- result = iconv(cd, NULL, NULL, (char **) &out_p, &out_left);
- out_size = bsz - out_left;
- if (result != (size_t)(-1)) {
- break;
- }
- if (errno == E2BIG) {
- bsz += 16;
- tmp_buf = (char *) erealloc(out_buf, bsz);
- out_p = out_buf = tmp_buf;
- out_p += out_size;
- out_left = bsz - out_size;
- } else {
- break;
- }
- }
- }
- iconv_close(cd);
- if (result == (size_t)(-1)) {
- switch (errno) {
- case EINVAL:
- retval = PHP_ICONV_ERR_ILLEGAL_CHAR;
- break;
- case EILSEQ:
- retval = PHP_ICONV_ERR_ILLEGAL_SEQ;
- break;
- case E2BIG:
- /* should not happen */
- retval = PHP_ICONV_ERR_TOO_BIG;
- break;
- default:
- /* other error */
- retval = PHP_ICONV_ERR_UNKNOWN;
- efree(out_buf);
- return PHP_ICONV_ERR_UNKNOWN;
- }
- }
- *out_p = '\0';
- *out = out_buf;
- *out_len = out_size;
- return retval;
- #endif
- }
- /* }}} */
- /* {{{ _php_iconv_strlen() */
- static php_iconv_err_t _php_iconv_strlen(unsigned int *pretval, const char *str, size_t nbytes, const char *enc)
- {
- char buf[GENERIC_SUPERSET_NBYTES*2];
- php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
- iconv_t cd;
- const char *in_p;
- size_t in_left;
- char *out_p;
- size_t out_left;
- unsigned int cnt;
- *pretval = (unsigned int)-1;
- cd = iconv_open(GENERIC_SUPERSET_NAME, enc);
- if (cd == (iconv_t)(-1)) {
- #if ICONV_SUPPORTS_ERRNO
- if (errno == EINVAL) {
- return PHP_ICONV_ERR_WRONG_CHARSET;
- } else {
- return PHP_ICONV_ERR_CONVERTER;
- }
- #else
- return PHP_ICONV_ERR_UNKNOWN;
- #endif
- }
- errno = out_left = 0;
- for (in_p = str, in_left = nbytes, cnt = 0; in_left > 0; cnt+=2) {
- size_t prev_in_left;
- out_p = buf;
- out_left = sizeof(buf);
- prev_in_left = in_left;
- if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
- if (prev_in_left == in_left) {
- break;
- }
- }
- }
- if (out_left > 0) {
- cnt -= out_left / GENERIC_SUPERSET_NBYTES;
- }
- #if ICONV_SUPPORTS_ERRNO
- switch (errno) {
- case EINVAL:
- err = PHP_ICONV_ERR_ILLEGAL_CHAR;
- break;
- case EILSEQ:
- err = PHP_ICONV_ERR_ILLEGAL_SEQ;
- break;
- case E2BIG:
- case 0:
- *pretval = cnt;
- break;
- default:
- err = PHP_ICONV_ERR_UNKNOWN;
- break;
- }
- #else
- *pretval = cnt;
- #endif
- iconv_close(cd);
- return err;
- }
- /* }}} */
- /* {{{ _php_iconv_substr() */
- static php_iconv_err_t _php_iconv_substr(smart_str *pretval,
- const char *str, size_t nbytes, int offset, int len, const char *enc)
- {
- char buf[GENERIC_SUPERSET_NBYTES];
- php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
- iconv_t cd1, cd2;
- const char *in_p;
- size_t in_left;
- char *out_p;
- size_t out_left;
- unsigned int cnt;
- int total_len;
- err = _php_iconv_strlen(&total_len, str, nbytes, enc);
- if (err != PHP_ICONV_ERR_SUCCESS) {
- return err;
- }
- if (len < 0) {
- if ((len += (total_len - offset)) < 0) {
- return PHP_ICONV_ERR_SUCCESS;
- }
- }
- if (offset < 0) {
- if ((offset += total_len) < 0) {
- return PHP_ICONV_ERR_SUCCESS;
- }
- }
- if(len > total_len) {
- len = total_len;
- }
- if (offset >= total_len) {
- return PHP_ICONV_ERR_SUCCESS;
- }
- if ((offset + len) > total_len ) {
- /* trying to compute the length */
- len = total_len - offset;
- }
- if (len == 0) {
- smart_str_appendl(pretval, "", 0);
- smart_str_0(pretval);
- return PHP_ICONV_ERR_SUCCESS;
- }
- cd1 = iconv_open(GENERIC_SUPERSET_NAME, enc);
- if (cd1 == (iconv_t)(-1)) {
- #if ICONV_SUPPORTS_ERRNO
- if (errno == EINVAL) {
- return PHP_ICONV_ERR_WRONG_CHARSET;
- } else {
- return PHP_ICONV_ERR_CONVERTER;
- }
- #else
- return PHP_ICONV_ERR_UNKNOWN;
- #endif
- }
- cd2 = (iconv_t)NULL;
- errno = 0;
- for (in_p = str, in_left = nbytes, cnt = 0; in_left > 0 && len > 0; ++cnt) {
- size_t prev_in_left;
- out_p = buf;
- out_left = sizeof(buf);
- prev_in_left = in_left;
- if (iconv(cd1, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
- if (prev_in_left == in_left) {
- break;
- }
- }
- if (cnt >= (unsigned int)offset) {
- if (cd2 == (iconv_t)NULL) {
- cd2 = iconv_open(enc, GENERIC_SUPERSET_NAME);
- if (cd2 == (iconv_t)(-1)) {
- cd2 = (iconv_t)NULL;
- #if ICONV_SUPPORTS_ERRNO
- if (errno == EINVAL) {
- err = PHP_ICONV_ERR_WRONG_CHARSET;
- } else {
- err = PHP_ICONV_ERR_CONVERTER;
- }
- #else
- err = PHP_ICONV_ERR_UNKNOWN;
- #endif
- break;
- }
- }
- if (_php_iconv_appendl(pretval, buf, sizeof(buf), cd2) != PHP_ICONV_ERR_SUCCESS) {
- break;
- }
- --len;
- }
- }
- #if ICONV_SUPPORTS_ERRNO
- switch (errno) {
- case EINVAL:
- err = PHP_ICONV_ERR_ILLEGAL_CHAR;
- break;
- case EILSEQ:
- err = PHP_ICONV_ERR_ILLEGAL_SEQ;
- break;
- case E2BIG:
- break;
- }
- #endif
- if (err == PHP_ICONV_ERR_SUCCESS) {
- if (cd2 != (iconv_t)NULL) {
- _php_iconv_appendl(pretval, NULL, 0, cd2);
- }
- smart_str_0(pretval);
- }
- if (cd1 != (iconv_t)NULL) {
- iconv_close(cd1);
- }
- if (cd2 != (iconv_t)NULL) {
- iconv_close(cd2);
- }
- return err;
- }
- /* }}} */
- /* {{{ _php_iconv_strpos() */
- static php_iconv_err_t _php_iconv_strpos(unsigned int *pretval,
- const char *haystk, size_t haystk_nbytes,
- const char *ndl, size_t ndl_nbytes,
- int offset, const char *enc)
- {
- char buf[GENERIC_SUPERSET_NBYTES];
- php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
- iconv_t cd;
- const char *in_p;
- size_t in_left;
- char *out_p;
- size_t out_left;
- unsigned int cnt;
- char *ndl_buf;
- const char *ndl_buf_p;
- size_t ndl_buf_len, ndl_buf_left;
- unsigned int match_ofs;
- *pretval = (unsigned int)-1;
- err = php_iconv_string(ndl, ndl_nbytes,
- &ndl_buf, &ndl_buf_len, GENERIC_SUPERSET_NAME, enc);
- if (err != PHP_ICONV_ERR_SUCCESS) {
- if (ndl_buf != NULL) {
- efree(ndl_buf);
- }
- return err;
- }
- cd = iconv_open(GENERIC_SUPERSET_NAME, enc);
- if (cd == (iconv_t)(-1)) {
- if (ndl_buf != NULL) {
- efree(ndl_buf);
- }
- #if ICONV_SUPPORTS_ERRNO
- if (errno == EINVAL) {
- return PHP_ICONV_ERR_WRONG_CHARSET;
- } else {
- return PHP_ICONV_ERR_CONVERTER;
- }
- #else
- return PHP_ICONV_ERR_UNKNOWN;
- #endif
- }
- ndl_buf_p = ndl_buf;
- ndl_buf_left = ndl_buf_len;
- match_ofs = (unsigned int)-1;
- for (in_p = haystk, in_left = haystk_nbytes, cnt = 0; in_left > 0; ++cnt) {
- size_t prev_in_left;
- out_p = buf;
- out_left = sizeof(buf);
- prev_in_left = in_left;
- if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
- if (prev_in_left == in_left) {
- #if ICONV_SUPPORTS_ERRNO
- switch (errno) {
- case EINVAL:
- err = PHP_ICONV_ERR_ILLEGAL_CHAR;
- break;
- case EILSEQ:
- err = PHP_ICONV_ERR_ILLEGAL_SEQ;
- break;
- case E2BIG:
- break;
- default:
- err = PHP_ICONV_ERR_UNKNOWN;
- break;
- }
- #endif
- break;
- }
- }
- if (offset >= 0) {
- if (cnt >= (unsigned int)offset) {
- if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) {
- if (match_ofs == (unsigned int)-1) {
- match_ofs = cnt;
- }
- ndl_buf_p += GENERIC_SUPERSET_NBYTES;
- ndl_buf_left -= GENERIC_SUPERSET_NBYTES;
- if (ndl_buf_left == 0) {
- *pretval = match_ofs;
- break;
- }
- } else {
- unsigned int i, j, lim;
- i = 0;
- j = GENERIC_SUPERSET_NBYTES;
- lim = (unsigned int)(ndl_buf_p - ndl_buf);
- while (j < lim) {
- if (_php_iconv_memequal(&ndl_buf[j], &ndl_buf[i],
- GENERIC_SUPERSET_NBYTES)) {
- i += GENERIC_SUPERSET_NBYTES;
- } else {
- j -= i;
- i = 0;
- }
- j += GENERIC_SUPERSET_NBYTES;
- }
- if (_php_iconv_memequal(buf, &ndl_buf[i], sizeof(buf))) {
- match_ofs += (lim - i) / GENERIC_SUPERSET_NBYTES;
- i += GENERIC_SUPERSET_NBYTES;
- ndl_buf_p = &ndl_buf[i];
- ndl_buf_left = ndl_buf_len - i;
- } else {
- match_ofs = (unsigned int)-1;
- ndl_buf_p = ndl_buf;
- ndl_buf_left = ndl_buf_len;
- }
- }
- }
- } else {
- if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) {
- if (match_ofs == (unsigned int)-1) {
- match_ofs = cnt;
- }
- ndl_buf_p += GENERIC_SUPERSET_NBYTES;
- ndl_buf_left -= GENERIC_SUPERSET_NBYTES;
- if (ndl_buf_left == 0) {
- *pretval = match_ofs;
- ndl_buf_p = ndl_buf;
- ndl_buf_left = ndl_buf_len;
- match_ofs = -1;
- }
- } else {
- unsigned int i, j, lim;
- i = 0;
- j = GENERIC_SUPERSET_NBYTES;
- lim = (unsigned int)(ndl_buf_p - ndl_buf);
- while (j < lim) {
- if (_php_iconv_memequal(&ndl_buf[j], &ndl_buf[i],
- GENERIC_SUPERSET_NBYTES)) {
- i += GENERIC_SUPERSET_NBYTES;
- } else {
- j -= i;
- i = 0;
- }
- j += GENERIC_SUPERSET_NBYTES;
- }
- if (_php_iconv_memequal(buf, &ndl_buf[i], sizeof(buf))) {
- match_ofs += (lim - i) / GENERIC_SUPERSET_NBYTES;
- i += GENERIC_SUPERSET_NBYTES;
- ndl_buf_p = &ndl_buf[i];
- ndl_buf_left = ndl_buf_len - i;
- } else {
- match_ofs = (unsigned int)-1;
- ndl_buf_p = ndl_buf;
- ndl_buf_left = ndl_buf_len;
- }
- }
- }
- }
- if (ndl_buf) {
- efree(ndl_buf);
- }
- iconv_close(cd);
- return err;
- }
- /* }}} */
- /* {{{ _php_iconv_mime_encode() */
- static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fname, size_t fname_nbytes, const char *fval, size_t fval_nbytes, unsigned int max_line_len, const char *lfchars, php_iconv_enc_scheme_t enc_scheme, const char *out_charset, const char *enc)
- {
- php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
- iconv_t cd = (iconv_t)(-1), cd_pl = (iconv_t)(-1);
- unsigned int char_cnt = 0;
- size_t out_charset_len;
- size_t lfchars_len;
- char *buf = NULL;
- char *encoded = NULL;
- size_t encoded_len;
- const char *in_p;
- size_t in_left;
- char *out_p;
- size_t out_left;
- static int qp_table[256] = {
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x00 */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 */
- 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20 */
- 1, 1, 1, 1, 1, 1, 1 ,1, 1, 1, 1, 1, 1, 3, 1, 3, /* 0x30 */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x50 */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, /* 0x70 */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x80 */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x90 */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xA0 */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xB0 */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xC0 */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xD0 */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xE0 */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 /* 0xF0 */
- };
- out_charset_len = strlen(out_charset);
- lfchars_len = strlen(lfchars);
- if ((fname_nbytes + 2) >= max_line_len
- || (out_charset_len + 12) >= max_line_len) {
- /* field name is too long */
- err = PHP_ICONV_ERR_TOO_BIG;
- goto out;
- }
- cd_pl = iconv_open(ICONV_ASCII_ENCODING, enc);
- if (cd_pl == (iconv_t)(-1)) {
- #if ICONV_SUPPORTS_ERRNO
- if (errno == EINVAL) {
- err = PHP_ICONV_ERR_WRONG_CHARSET;
- } else {
- err = PHP_ICONV_ERR_CONVERTER;
- }
- #else
- err = PHP_ICONV_ERR_UNKNOWN;
- #endif
- goto out;
- }
- cd = iconv_open(out_charset, enc);
- if (cd == (iconv_t)(-1)) {
- #if ICONV_SUPPORTS_ERRNO
- if (errno == EINVAL) {
- err = PHP_ICONV_ERR_WRONG_CHARSET;
- } else {
- err = PHP_ICONV_ERR_CONVERTER;
- }
- #else
- err = PHP_ICONV_ERR_UNKNOWN;
- #endif
- goto out;
- }
- buf = safe_emalloc(1, max_line_len, 5);
- char_cnt = max_line_len;
- _php_iconv_appendl(pretval, fname, fname_nbytes, cd_pl);
- char_cnt -= fname_nbytes;
- smart_str_appendl(pretval, ": ", sizeof(": ") - 1);
- char_cnt -= 2;
- in_p = fval;
- in_left = fval_nbytes;
- do {
- size_t prev_in_left;
- size_t out_size;
- if (char_cnt < (out_charset_len + 12)) {
- /* lfchars must be encoded in ASCII here*/
- smart_str_appendl(pretval, lfchars, lfchars_len);
- smart_str_appendc(pretval, ' ');
- char_cnt = max_line_len - 1;
- }
- smart_str_appendl(pretval, "=?", sizeof("=?") - 1);
- char_cnt -= 2;
- smart_str_appendl(pretval, out_charset, out_charset_len);
- char_cnt -= out_charset_len;
- smart_str_appendc(pretval, '?');
- char_cnt --;
- switch (enc_scheme) {
- case PHP_ICONV_ENC_SCHEME_BASE64: {
- size_t ini_in_left;
- const char *ini_in_p;
- size_t out_reserved = 4;
- int dummy;
- smart_str_appendc(pretval, 'B');
- char_cnt--;
- smart_str_appendc(pretval, '?');
- char_cnt--;
- prev_in_left = ini_in_left = in_left;
- ini_in_p = in_p;
- out_size = (char_cnt - 2) / 4 * 3;
- for (;;) {
- out_p = buf;
- if (out_size <= out_reserved) {
- err = PHP_ICONV_ERR_TOO_BIG;
- goto out;
- }
- out_left = out_size - out_reserved;
- if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
- #if ICONV_SUPPORTS_ERRNO
- switch (errno) {
- case EINVAL:
- err = PHP_ICONV_ERR_ILLEGAL_CHAR;
- goto out;
- case EILSEQ:
- err = PHP_ICONV_ERR_ILLEGAL_SEQ;
- goto out;
- case E2BIG:
- if (prev_in_left == in_left) {
- err = PHP_ICONV_ERR_TOO_BIG;
- goto out;
- }
- break;
- default:
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- #else
- if (prev_in_left == in_left) {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- #endif
- }
- out_left += out_reserved;
- if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) {
- #if ICONV_SUPPORTS_ERRNO
- if (errno != E2BIG) {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- #else
- if (out_left != 0) {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- #endif
- } else {
- break;
- }
- if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- out_reserved += 4;
- in_left = ini_in_left;
- in_p = ini_in_p;
- }
- prev_in_left = in_left;
- encoded = (char *) php_base64_encode((unsigned char *) buf, (int)(out_size - out_left), &dummy);
- encoded_len = (size_t)dummy;
- if (char_cnt < encoded_len) {
- /* something went wrong! */
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- smart_str_appendl(pretval, encoded, encoded_len);
- char_cnt -= encoded_len;
- smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
- char_cnt -= 2;
- efree(encoded);
- encoded = NULL;
- } break; /* case PHP_ICONV_ENC_SCHEME_BASE64: */
- case PHP_ICONV_ENC_SCHEME_QPRINT: {
- size_t ini_in_left;
- const char *ini_in_p;
- const unsigned char *p;
- size_t nbytes_required;
- smart_str_appendc(pretval, 'Q');
- char_cnt--;
- smart_str_appendc(pretval, '?');
- char_cnt--;
- prev_in_left = ini_in_left = in_left;
- ini_in_p = in_p;
- for (out_size = (char_cnt - 2) / 3; out_size > 0;) {
- size_t prev_out_left;
- nbytes_required = 0;
- out_p = buf;
- out_left = out_size;
- if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
- #if ICONV_SUPPORTS_ERRNO
- switch (errno) {
- case EINVAL:
- err = PHP_ICONV_ERR_ILLEGAL_CHAR;
- goto out;
- case EILSEQ:
- err = PHP_ICONV_ERR_ILLEGAL_SEQ;
- goto out;
- case E2BIG:
- if (prev_in_left == in_left) {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- break;
- default:
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- #else
- if (prev_in_left == in_left) {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- #endif
- }
- prev_out_left = out_left;
- if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) {
- #if ICONV_SUPPORTS_ERRNO
- if (errno != E2BIG) {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- #else
- if (out_left == prev_out_left) {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- #endif
- }
- for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
- nbytes_required += qp_table[*p];
- }
- if (nbytes_required <= char_cnt - 2) {
- break;
- }
- out_size -= ((nbytes_required - (char_cnt - 2)) + 1) / 3;
- in_left = ini_in_left;
- in_p = ini_in_p;
- }
- for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
- if (qp_table[*p] == 1) {
- smart_str_appendc(pretval, *(char *)p);
- char_cnt--;
- } else {
- static char qp_digits[] = "0123456789ABCDEF";
- smart_str_appendc(pretval, '=');
- smart_str_appendc(pretval, qp_digits[(*p >> 4) & 0x0f]);
- smart_str_appendc(pretval, qp_digits[(*p & 0x0f)]);
- char_cnt -= 3;
- }
- }
- smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
- char_cnt -= 2;
- if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- } break; /* case PHP_ICONV_ENC_SCHEME_QPRINT: */
- }
- } while (in_left > 0);
- smart_str_0(pretval);
- out:
- if (cd != (iconv_t)(-1)) {
- iconv_close(cd);
- }
- if (cd_pl != (iconv_t)(-1)) {
- iconv_close(cd_pl);
- }
- if (encoded != NULL) {
- efree(encoded);
- }
- if (buf != NULL) {
- efree(buf);
- }
- return err;
- }
- /* }}} */
- /* {{{ _php_iconv_mime_decode() */
- static php_iconv_err_t _php_iconv_mime_decode(smart_str *pretval, const char *str, size_t str_nbytes, const char *enc, const char **next_pos, int mode)
- {
- php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
- iconv_t cd = (iconv_t)(-1), cd_pl = (iconv_t)(-1);
- const char *p1;
- size_t str_left;
- unsigned int scan_stat = 0;
- const char *csname = NULL;
- size_t csname_len;
- const char *encoded_text = NULL;
- size_t encoded_text_len = 0;
- const char *encoded_word = NULL;
- const char *spaces = NULL;
- php_iconv_enc_scheme_t enc_scheme = PHP_ICONV_ENC_SCHEME_BASE64;
- if (next_pos != NULL) {
- *next_pos = NULL;
- }
- cd_pl = iconv_open(enc, ICONV_ASCII_ENCODING);
- if (cd_pl == (iconv_t)(-1)) {
- #if ICONV_SUPPORTS_ERRNO
- if (errno == EINVAL) {
- err = PHP_ICONV_ERR_WRONG_CHARSET;
- } else {
- err = PHP_ICONV_ERR_CONVERTER;
- }
- #else
- err = PHP_ICONV_ERR_UNKNOWN;
- #endif
- goto out;
- }
- p1 = str;
- for (str_left = str_nbytes; str_left > 0; str_left--, p1++) {
- int eos = 0;
- switch (scan_stat) {
- case 0: /* expecting any character */
- switch (*p1) {
- case '\r': /* part of an EOL sequence? */
- scan_stat = 7;
- break;
- case '\n':
- scan_stat = 8;
- break;
- case '=': /* first letter of an encoded chunk */
- encoded_word = p1;
- scan_stat = 1;
- break;
- case ' ': case '\t': /* a chunk of whitespaces */
- spaces = p1;
- scan_stat = 11;
- break;
- default: /* first letter of a non-encoded word */
- _php_iconv_appendc(pretval, *p1, cd_pl);
- encoded_word = NULL;
- if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
- scan_stat = 12;
- }
- break;
- }
- break;
- case 1: /* expecting a delimiter */
- if (*p1 != '?') {
- err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
- if (err != PHP_ICONV_ERR_SUCCESS) {
- goto out;
- }
- encoded_word = NULL;
- if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
- scan_stat = 12;
- } else {
- scan_stat = 0;
- }
- break;
- }
- csname = p1 + 1;
- scan_stat = 2;
- break;
- case 2: /* expecting a charset name */
- switch (*p1) {
- case '?': /* normal delimiter: encoding scheme follows */
- scan_stat = 3;
- break;
- case '*': /* new style delimiter: locale id follows */
- scan_stat = 10;
- break;
- }
- if (scan_stat != 2) {
- char tmpbuf[80];
- if (csname == NULL) {
- err = PHP_ICONV_ERR_MALFORMED;
- goto out;
- }
- csname_len = (size_t)(p1 - csname);
- if (csname_len > sizeof(tmpbuf) - 1) {
- if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
- err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
- if (err != PHP_ICONV_ERR_SUCCESS) {
- goto out;
- }
- encoded_word = NULL;
- if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
- scan_stat = 12;
- } else {
- scan_stat = 0;
- }
- break;
- } else {
- err = PHP_ICONV_ERR_MALFORMED;
- goto out;
- }
- }
- memcpy(tmpbuf, csname, csname_len);
- tmpbuf[csname_len] = '\0';
- if (cd != (iconv_t)(-1)) {
- iconv_close(cd);
- }
- cd = iconv_open(enc, tmpbuf);
- if (cd == (iconv_t)(-1)) {
- if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
- /* Bad character set, but the user wants us to
- * press on. In this case, we'll just insert the
- * undecoded encoded word, since there isn't really
- * a more sensible behaviour available; the only
- * other options are to swallow the encoded word
- * entirely or decode it with an arbitrarily chosen
- * single byte encoding, both of which seem to have
- * a higher WTF factor than leaving it undecoded.
- *
- * Given this approach, we need to skip ahead to
- * the end of the encoded word. */
- int qmarks = 2;
- while (qmarks > 0 && str_left > 1) {
- if (*(++p1) == '?') {
- --qmarks;
- }
- --str_left;
- }
- /* Look ahead to check for the terminating = that
- * should be there as well; if it's there, we'll
- * also include that. If it's not, there isn't much
- * we can do at this point. */
- if (*(p1 + 1) == '=') {
- ++p1;
- --str_left;
- }
- err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
- if (err != PHP_ICONV_ERR_SUCCESS) {
- goto out;
- }
- /* Let's go back and see if there are further
- * encoded words or bare content, and hope they
- * might actually have a valid character set. */
- scan_stat = 12;
- break;
- } else {
- #if ICONV_SUPPORTS_ERRNO
- if (errno == EINVAL) {
- err = PHP_ICONV_ERR_WRONG_CHARSET;
- } else {
- err = PHP_ICONV_ERR_CONVERTER;
- }
- #else
- err = PHP_ICONV_ERR_UNKNOWN;
- #endif
- goto out;
- }
- }
- }
- break;
- case 3: /* expecting a encoding scheme specifier */
- switch (*p1) {
- case 'b':
- case 'B':
- enc_scheme = PHP_ICONV_ENC_SCHEME_BASE64;
- scan_stat = 4;
- break;
- case 'q':
- case 'Q':
- enc_scheme = PHP_ICONV_ENC_SCHEME_QPRINT;
- scan_stat = 4;
- break;
- default:
- if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
- err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
- if (err != PHP_ICONV_ERR_SUCCESS) {
- goto out;
- }
- encoded_word = NULL;
- if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
- scan_stat = 12;
- } else {
- scan_stat = 0;
- }
- break;
- } else {
- err = PHP_ICONV_ERR_MALFORMED;
- goto out;
- }
- }
- break;
- case 4: /* expecting a delimiter */
- if (*p1 != '?') {
- if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
- /* pass the entire chunk through the converter */
- err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
- if (err != PHP_ICONV_ERR_SUCCESS) {
- goto out;
- }
- encoded_word = NULL;
- if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
- scan_stat = 12;
- } else {
- scan_stat = 0;
- }
- break;
- } else {
- err = PHP_ICONV_ERR_MALFORMED;
- goto out;
- }
- }
- encoded_text = p1 + 1;
- scan_stat = 5;
- break;
- case 5: /* expecting an encoded portion */
- if (*p1 == '?') {
- encoded_text_len = (size_t)(p1 - encoded_text);
- scan_stat = 6;
- }
- break;
- case 7: /* expecting a "\n" character */
- if (*p1 == '\n') {
- scan_stat = 8;
- } else {
- /* bare CR */
- _php_iconv_appendc(pretval, '\r', cd_pl);
- _php_iconv_appendc(pretval, *p1, cd_pl);
- scan_stat = 0;
- }
- break;
- case 8: /* checking whether the following line is part of a
- folded header */
- if (*p1 != ' ' && *p1 != '\t') {
- --p1;
- str_left = 1; /* quit_loop */
- break;
- }
- if (encoded_word == NULL) {
- _php_iconv_appendc(pretval, ' ', cd_pl);
- }
- spaces = NULL;
- scan_stat = 11;
- break;
- case 6: /* expecting a End-Of-Chunk character "=" */
- if (*p1 != '=') {
- if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
- /* pass the entire chunk through the converter */
- err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
- if (err != PHP_ICONV_ERR_SUCCESS) {
- goto out;
- }
- encoded_word = NULL;
- if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
- scan_stat = 12;
- } else {
- scan_stat = 0;
- }
- break;
- } else {
- err = PHP_ICONV_ERR_MALFORMED;
- goto out;
- }
- }
- scan_stat = 9;
- if (str_left == 1) {
- eos = 1;
- } else {
- break;
- }
- case 9: /* choice point, seeing what to do next.*/
- switch (*p1) {
- default:
- /* Handle non-RFC-compliant formats
- *
- * RFC2047 requires the character that comes right
- * after an encoded word (chunk) to be a whitespace,
- * while there are lots of broken implementations that
- * generate such malformed headers that don't fulfill
- * that requirement.
- */
- if (!eos) {
- if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
- /* pass the entire chunk through the converter */
- err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
- if (err != PHP_ICONV_ERR_SUCCESS) {
- goto out;
- }
- scan_stat = 12;
- break;
- }
- }
- /* break is omitted intentionally */
- case '\r': case '\n': case ' ': case '\t': {
- char *decoded_text;
- size_t decoded_text_len;
- int dummy;
- switch (enc_scheme) {
- case PHP_ICONV_ENC_SCHEME_BASE64:
- decoded_text = (char *)php_base64_decode((unsigned char*)encoded_text, (int)encoded_text_len, &dummy);
- decoded_text_len = (size_t)dummy;
- break;
- case PHP_ICONV_ENC_SCHEME_QPRINT:
- decoded_text = (char *)php_quot_print_decode((unsigned char*)encoded_text, (int)encoded_text_len, &decoded_text_len, 1);
- break;
- default:
- decoded_text = NULL;
- break;
- }
- if (decoded_text == NULL) {
- if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
- /* pass the entire chunk through the converter */
- err = _php_iconv_appendl(pretval, encoded_word, (size_t)((p1 + 1) - encoded_word), cd_pl);
- if (err != PHP_ICONV_ERR_SUCCESS) {
- goto out;
- }
- encoded_word = NULL;
- if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
- scan_stat = 12;
- } else {
- scan_stat = 0;
- }
- break;
- } else {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- }
- err = _php_iconv_appendl(pretval, decoded_text, decoded_text_len, cd);
- efree(decoded_text);
- if (err != PHP_ICONV_ERR_SUCCESS) {
- if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
- /* pass the entire chunk through the converter */
- err = _php_iconv_appendl(pretval, encoded_word, (size_t)(p1 - encoded_word), cd_pl);
- encoded_word = NULL;
- if (err != PHP_ICONV_ERR_SUCCESS) {
- break;
- }
- } else {
- goto out;
- }
- }
- if (eos) { /* reached end-of-string. done. */
- scan_stat = 0;
- break;
- }
- switch (*p1) {
- case '\r': /* part of an EOL sequence? */
- scan_stat = 7;
- break;
- case '\n':
- scan_stat = 8;
- break;
- case '=': /* first letter of an encoded chunk */
- scan_stat = 1;
- break;
- case ' ': case '\t': /* medial whitespaces */
- spaces = p1;
- scan_stat = 11;
- break;
- default: /* first letter of a non-encoded word */
- _php_iconv_appendc(pretval, *p1, cd_pl);
- scan_stat = 12;
- break;
- }
- } break;
- }
- break;
- case 10: /* expects a language specifier. dismiss it for now */
- if (*p1 == '?') {
- scan_stat = 3;
- }
- break;
- case 11: /* expecting a chunk of whitespaces */
- switch (*p1) {
- case '\r': /* part of an EOL sequence? */
- scan_stat = 7;
- break;
- case '\n':
- scan_stat = 8;
- break;
- case '=': /* first letter of an encoded chunk */
- if (spaces != NULL && encoded_word == NULL) {
- _php_iconv_appendl(pretval, spaces, (size_t)(p1 - spaces), cd_pl);
- spaces = NULL;
- }
- encoded_word = p1;
- scan_stat = 1;
- break;
- case ' ': case '\t':
- break;
- default: /* first letter of a non-encoded word */
- if (spaces != NULL) {
- _php_iconv_appendl(pretval, spaces, (size_t)(p1 - spaces), cd_pl);
- spaces = NULL;
- }
- _php_iconv_appendc(pretval, *p1, cd_pl);
- encoded_word = NULL;
- if ((mode & PHP_ICONV_MIME_DECODE_STRICT)) {
- scan_stat = 12;
- } else {
- scan_stat = 0;
- }
- break;
- }
- break;
- case 12: /* expecting a non-encoded word */
- switch (*p1) {
- case '\r': /* part of an EOL sequence? */
- scan_stat = 7;
- break;
- case '\n':
- scan_stat = 8;
- break;
- case ' ': case '\t':
- spaces = p1;
- scan_stat = 11;
- break;
- case '=': /* first letter of an encoded chunk */
- if (!(mode & PHP_ICONV_MIME_DECODE_STRICT)) {
- encoded_word = p1;
- scan_stat = 1;
- break;
- }
- /* break is omitted intentionally */
- default:
- _php_iconv_appendc(pretval, *p1, cd_pl);
- break;
- }
- break;
- }
- }
- switch (scan_stat) {
- case 0: case 8: case 11: case 12:
- break;
- default:
- if ((mode & PHP_ICONV_MIME_DECODE_CONTINUE_ON_ERROR)) {
- if (scan_stat == 1) {
- _php_iconv_appendc(pretval, '=', cd_pl);
- }
- err = PHP_ICONV_ERR_SUCCESS;
- } else {
- err = PHP_ICONV_ERR_MALFORMED;
- goto out;
- }
- }
- if (next_pos != NULL) {
- *next_pos = p1;
- }
- smart_str_0(pretval);
- out:
- if (cd != (iconv_t)(-1)) {
- iconv_close(cd);
- }
- if (cd_pl != (iconv_t)(-1)) {
- iconv_close(cd_pl);
- }
- return err;
- }
- /* }}} */
- /* {{{ php_iconv_show_error() */
- static void _php_iconv_show_error(php_iconv_err_t err, const char *out_charset, const char *in_charset TSRMLS_DC)
- {
- switch (err) {
- case PHP_ICONV_ERR_SUCCESS:
- break;
- case PHP_ICONV_ERR_CONVERTER:
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot open converter");
- break;
- case PHP_ICONV_ERR_WRONG_CHARSET:
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong charset, conversion from `%s' to `%s' is not allowed",
- in_charset, out_charset);
- break;
- case PHP_ICONV_ERR_ILLEGAL_CHAR:
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected an incomplete multibyte character in input string");
- break;
- case PHP_ICONV_ERR_ILLEGAL_SEQ:
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected an illegal character in input string");
- break;
- case PHP_ICONV_ERR_TOO_BIG:
- /* should not happen */
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Buffer length exceeded");
- break;
- case PHP_ICONV_ERR_MALFORMED:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Malformed string");
- break;
- default:
- /* other error */
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown error (%d)", errno);
- break;
- }
- }
- /* }}} */
- /* {{{ proto int iconv_strlen(string str [, string charset])
- Returns the character count of str */
- PHP_FUNCTION(iconv_strlen)
- {
- char *charset = get_internal_encoding(TSRMLS_C);
- int charset_len = 0;
- char *str;
- int str_len;
- php_iconv_err_t err;
- unsigned int retval;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
- &str, &str_len, &charset, &charset_len) == FAILURE) {
- RETURN_FALSE;
- }
- if (charset_len >= ICONV_CSNMAXLEN) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
- RETURN_FALSE;
- }
- err = _php_iconv_strlen(&retval, str, str_len, charset);
- _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
- if (err == PHP_ICONV_ERR_SUCCESS) {
- RETVAL_LONG(retval);
- } else {
- RETVAL_FALSE;
- }
- }
- /* }}} */
- /* {{{ proto string iconv_substr(string str, int offset, [int length, string charset])
- Returns specified part of a string */
- PHP_FUNCTION(iconv_substr)
- {
- char *charset = get_internal_encoding(TSRMLS_C);
- int charset_len = 0;
- char *str;
- int str_len;
- long offset, length = 0;
- php_iconv_err_t err;
- smart_str retval = {0};
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|ls",
- &str, &str_len, &offset, &length,
- &charset, &charset_len) == FAILURE) {
- RETURN_FALSE;
- }
- if (charset_len >= ICONV_CSNMAXLEN) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
- RETURN_FALSE;
- }
- if (ZEND_NUM_ARGS() < 3) {
- length = str_len;
- }
- err = _php_iconv_substr(&retval, str, str_len, offset, length, charset);
- _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
- if (err == PHP_ICONV_ERR_SUCCESS && str != NULL && retval.c != NULL) {
- RETURN_STRINGL(retval.c, retval.len, 0);
- }
- smart_str_free(&retval);
- RETURN_FALSE;
- }
- /* }}} */
- /* {{{ proto int iconv_strpos(string haystack, string needle [, int offset [, string charset]])
- Finds position of first occurrence of needle within part of haystack beginning with offset */
- PHP_FUNCTION(iconv_strpos)
- {
- char *charset = get_internal_encoding(TSRMLS_C);
- int charset_len = 0;
- char *haystk;
- int haystk_len;
- char *ndl;
- int ndl_len;
- long offset = 0;
- php_iconv_err_t err;
- unsigned int retval;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls",
- &haystk, &haystk_len, &ndl, &ndl_len,
- &offset, &charset, &charset_len) == FAILURE) {
- RETURN_FALSE;
- }
- if (charset_len >= ICONV_CSNMAXLEN) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
- RETURN_FALSE;
- }
- if (offset < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string.");
- RETURN_FALSE;
- }
- if (ndl_len < 1) {
- RETURN_FALSE;
- }
- err = _php_iconv_strpos(&retval, haystk, haystk_len, ndl, ndl_len,
- offset, charset);
- _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
- if (err == PHP_ICONV_ERR_SUCCESS && retval != (unsigned int)-1) {
- RETVAL_LONG((long)retval);
- } else {
- RETVAL_FALSE;
- }
- }
- /* }}} */
- /* {{{ proto int iconv_strrpos(string haystack, string needle [, string charset])
- Finds position of last occurrence of needle within part of haystack beginning with offset */
- PHP_FUNCTION(iconv_strrpos)
- {
- char *charset = get_internal_encoding(TSRMLS_C);
- int charset_len = 0;
- char *haystk;
- int haystk_len;
- char *ndl;
- int ndl_len;
- php_iconv_err_t err;
- unsigned int retval;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s",
- &haystk, &haystk_len, &ndl, &ndl_len,
- &charset, &charset_len) == FAILURE) {
- RETURN_FALSE;
- }
- if (ndl_len < 1) {
- RETURN_FALSE;
- }
- if (charset_len >= ICONV_CSNMAXLEN) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
- RETURN_FALSE;
- }
- err = _php_iconv_strpos(&retval, haystk, haystk_len, ndl, ndl_len,
- -1, charset);
- _php_iconv_show_error(err, GENERIC_SUPERSET_NAME, charset TSRMLS_CC);
- if (err == PHP_ICONV_ERR_SUCCESS && retval != (unsigned int)-1) {
- RETVAL_LONG((long)retval);
- } else {
- RETVAL_FALSE;
- }
- }
- /* }}} */
- /* {{{ proto string iconv_mime_encode(string field_name, string field_value [, array preference])
- Composes a mime header field with field_name and field_value in a specified scheme */
- PHP_FUNCTION(iconv_mime_encode)
- {
- const char *field_name = NULL;
- int field_name_len;
- const char *field_value = NULL;
- int field_value_len;
- zval *pref = NULL;
- zval tmp_zv, *tmp_zv_p = NULL;
- smart_str retval = {0};
- php_iconv_err_t err;
- const char *in_charset = get_internal_encoding(TSRMLS_C);
- const char *out_charset = in_charset;
- long line_len = 76;
- const char *lfchars = "\r\n";
- php_iconv_enc_scheme_t scheme_id = PHP_ICONV_ENC_SCHEME_BASE64;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a",
- &field_name, &field_name_len, &field_value, &field_value_len,
- &pref) == FAILURE) {
- RETURN_FALSE;
- }
- if (pref != NULL) {
- zval **ppval;
- if (zend_hash_find(Z_ARRVAL_P(pref), "scheme", sizeof("scheme"), (void **)&ppval) == SUCCESS) {
- if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
- switch (Z_STRVAL_PP(ppval)[0]) {
- case 'B': case 'b':
- scheme_id = PHP_ICONV_ENC_SCHEME_BASE64;
- break;
- case 'Q': case 'q':
- scheme_id = PHP_ICONV_ENC_SCHEME_QPRINT;
- break;
- }
- }
- }
- if (zend_hash_find(Z_ARRVAL_P(pref), "input-charset", sizeof("input-charset"), (void **)&ppval) == SUCCESS) {
- if (Z_STRLEN_PP(ppval) >= ICONV_CSNMAXLEN) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
- RETURN_FALSE;
- }
- if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
- in_charset = Z_STRVAL_PP(ppval);
- }
- }
- if (zend_hash_find(Z_ARRVAL_P(pref), "output-charset", sizeof("output-charset"), (void **)&ppval) == SUCCESS) {
- if (Z_STRLEN_PP(ppval) >= ICONV_CSNMAXLEN) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
- RETURN_FALSE;
- }
- if (Z_TYPE_PP(ppval) == IS_STRING && Z_STRLEN_PP(ppval) > 0) {
- out_charset = Z_STRVAL_PP(ppval);
- }
- }
- if (zend_hash_find(Z_ARRVAL_P(pref), "line-length", sizeof("line-length"), (void **)&ppval) == SUCCESS) {
- zval val, *pval = *ppval;
- if (Z_TYPE_P(pval) != IS_LONG) {
- val = *pval;
- zval_copy_ctor(&val);
- convert_to_long(&val);
- pval = &val;
- }
- line_len = Z_LVAL_P(pval);
- if (pval == &val) {
- zval_dtor(&val);
- }
- }
- if (zend_hash_find(Z_ARRVAL_P(pref), "line-break-chars", sizeof("line-break-chars"), (void **)&ppval) == SUCCESS) {
- if (Z_TYPE_PP(ppval) != IS_STRING) {
- tmp_zv = **ppval;
- zval_copy_ctor(&tmp_zv);
- convert_to_string(&tmp_zv);
- lfchars = Z_STRVAL(tmp_zv);
- tmp_zv_p = &tmp_zv;
- } else {
- lfchars = Z_STRVAL_PP(ppval);
- }
- }
- }
- err = _php_iconv_mime_encode(&retval, field_name, field_name_len,
- field_value, field_value_len, line_len, lfchars, scheme_id,
- out_charset, in_charset);
- _php_iconv_show_error(err, out_charset, in_charset TSRMLS_CC);
- if (err == PHP_ICONV_ERR_SUCCESS) {
- if (retval.c != NULL) {
- RETVAL_STRINGL(retval.c, retval.len, 0);
- } else {
- RETVAL_EMPTY_STRING();
- }
- } else {
- smart_str_free(&retval);
- RETVAL_FALSE;
- }
- if (tmp_zv_p != NULL) {
- zval_dtor(tmp_zv_p);
- }
- }
- /* }}} */
- /* {{{ proto string iconv_mime_decode(string encoded_string [, int mode, string charset])
- Decodes a mime header field */
- PHP_FUNCTION(iconv_mime_decode)
- {
- char *encoded_str;
- int encoded_str_len;
- char *charset = get_internal_encoding(TSRMLS_C);
- int charset_len = 0;
- long mode = 0;
- smart_str retval = {0};
- php_iconv_err_t err;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls",
- &encoded_str, &encoded_str_len, &mode, &charset, &charset_len) == FAILURE) {
- RETURN_FALSE;
- }
- if (charset_len >= ICONV_CSNMAXLEN) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
- RETURN_FALSE;
- }
- err = _php_iconv_mime_decode(&retval, encoded_str, encoded_str_len, charset, NULL, mode);
- _php_iconv_show_error(err, charset, "???" TSRMLS_CC);
- if (err == PHP_ICONV_ERR_SUCCESS) {
- if (retval.c != NULL) {
- RETVAL_STRINGL(retval.c, retval.len, 0);
- } else {
- RETVAL_EMPTY_STRING();
- }
- } else {
- smart_str_free(&retval);
- RETVAL_FALSE;
- }
- }
- /* }}} */
- /* {{{ proto array iconv_mime_decode_headers(string headers [, int mode, string charset])
- Decodes multiple mime header fields */
- PHP_FUNCTION(iconv_mime_decode_headers)
- {
- const char *encoded_str;
- int encoded_str_len;
- char *charset = get_internal_encoding(TSRMLS_C);
- int charset_len = 0;
- long mode = 0;
- php_iconv_err_t err = PHP_ICONV_ERR_SUCCESS;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls",
- &encoded_str, &encoded_str_len, &mode, &charset, &charset_len) == FAILURE) {
- RETURN_FALSE;
- }
- if (charset_len >= ICONV_CSNMAXLEN) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
- RETURN_FALSE;
- }
- array_init(return_value);
- while (encoded_str_len > 0) {
- smart_str decoded_header = {0};
- char *header_name = NULL;
- size_t header_name_len = 0;
- char *header_value = NULL;
- size_t header_value_len = 0;
- char *p, *limit;
- const char *next_pos;
- if (PHP_ICONV_ERR_SUCCESS != (err = _php_iconv_mime_decode(&decoded_header, encoded_str, encoded_str_len, charset, &next_pos, mode))) {
- smart_str_free(&decoded_header);
- break;
- }
- if (decoded_header.c == NULL) {
- break;
- }
- limit = decoded_header.c + decoded_header.len;
- for (p = decoded_header.c; p < limit; p++) {
- if (*p == ':') {
- *p = '\0';
- header_name = decoded_header.c;
- header_name_len = (p - decoded_header.c) + 1;
- while (++p < limit) {
- if (*p != ' ' && *p != '\t') {
- break;
- }
- }
- header_value = p;
- header_value_len = limit - p;
- break;
- }
- }
- if (header_name != NULL) {
- zval **elem, *new_elem;
- if (zend_hash_find(Z_ARRVAL_P(return_value), header_name, header_name_len, (void **)&elem) == SUCCESS) {
- if (Z_TYPE_PP(elem) != IS_ARRAY) {
- MAKE_STD_ZVAL(new_elem);
- array_init(new_elem);
- Z_ADDREF_PP(elem);
- add_next_index_zval(new_elem, *elem);
- zend_hash_update(Z_ARRVAL_P(return_value), header_name, header_name_len, (void *)&new_elem, sizeof(new_elem), NULL);
- elem = &new_elem;
- }
- add_next_index_stringl(*elem, header_value, header_value_len, 1);
- } else {
- add_assoc_stringl_ex(return_value, header_name, header_name_len, header_value, header_value_len, 1);
- }
- }
- encoded_str_len -= next_pos - encoded_str;
- encoded_str = next_pos;
- smart_str_free(&decoded_header);
- }
- if (err != PHP_ICONV_ERR_SUCCESS) {
- _php_iconv_show_error(err, charset, "???" TSRMLS_CC);
- zval_dtor(return_value);
- RETVAL_FALSE;
- }
- }
- /* }}} */
- /* {{{ proto string iconv(string in_charset, string out_charset, string str)
- Returns str converted to the out_charset character set */
- PHP_NAMED_FUNCTION(php_if_iconv)
- {
- char *in_charset, *out_charset, *in_buffer, *out_buffer;
- size_t out_len;
- int in_charset_len = 0, out_charset_len = 0, in_buffer_len;
- php_iconv_err_t err;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss",
- &in_charset, &in_charset_len, &out_charset, &out_charset_len, &in_buffer, &in_buffer_len) == FAILURE)
- return;
- if (in_charset_len >= ICONV_CSNMAXLEN || out_charset_len >= ICONV_CSNMAXLEN) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
- RETURN_FALSE;
- }
- err = php_iconv_string(in_buffer, (size_t)in_buffer_len,
- &out_buffer, &out_len, out_charset, in_charset);
- _php_iconv_show_error(err, out_charset, in_charset TSRMLS_CC);
- if (err == PHP_ICONV_ERR_SUCCESS && out_buffer != NULL) {
- RETVAL_STRINGL_CHECK(out_buffer, out_len, 0);
- } else {
- if (out_buffer != NULL) {
- efree(out_buffer);
- }
- RETURN_FALSE;
- }
- }
- /* }}} */
- /* {{{ proto bool iconv_set_encoding(string type, string charset)
- Sets internal encoding and output encoding for ob_iconv_handler() */
- PHP_FUNCTION(iconv_set_encoding)
- {
- char *type, *charset;
- int type_len, charset_len =0, retval;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &type, &type_len, &charset, &charset_len) == FAILURE)
- return;
- if (charset_len >= ICONV_CSNMAXLEN) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Charset parameter exceeds the maximum allowed length of %d characters", ICONV_CSNMAXLEN);
- RETURN_FALSE;
- }
- if(!strcasecmp("input_encoding", type)) {
- retval = zend_alter_ini_entry("iconv.input_encoding", sizeof("iconv.input_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
- } else if(!strcasecmp("output_encoding", type)) {
- retval = zend_alter_ini_entry("iconv.output_encoding", sizeof("iconv.output_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
- } else if(!strcasecmp("internal_encoding", type)) {
- retval = zend_alter_ini_entry("iconv.internal_encoding", sizeof("iconv.internal_encoding"), charset, charset_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
- } else {
- RETURN_FALSE;
- }
- if (retval == SUCCESS) {
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
- }
- /* }}} */
- /* {{{ proto mixed iconv_get_encoding([string type])
- Get internal encoding and output encoding for ob_iconv_handler() */
- PHP_FUNCTION(iconv_get_encoding)
- {
- char *type = "all";
- int type_len = sizeof("all")-1;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &type, &type_len) == FAILURE)
- return;
- if (!strcasecmp("all", type)) {
- array_init(return_value);
- add_assoc_string(return_value, "input_encoding", get_input_encoding(TSRMLS_C), 1);
- add_assoc_string(return_value, "output_encoding", get_output_encoding(TSRMLS_C), 1);
- add_assoc_string(return_value, "internal_encoding", get_internal_encoding(TSRMLS_C), 1);
- } else if (!strcasecmp("input_encoding", type)) {
- RETVAL_STRING(get_input_encoding(TSRMLS_C), 1);
- } else if (!strcasecmp("output_encoding", type)) {
- RETVAL_STRING(get_output_encoding(TSRMLS_C), 1);
- } else if (!strcasecmp("internal_encoding", type)) {
- RETVAL_STRING(get_internal_encoding(TSRMLS_C), 1);
- } else {
- RETURN_FALSE;
- }
- }
- /* }}} */
- /* {{{ iconv stream filter */
- typedef struct _php_iconv_stream_filter {
- iconv_t cd;
- int persistent;
- char *to_charset;
- size_t to_charset_len;
- char *from_charset;
- size_t from_charset_len;
- char stub[128];
- size_t stub_len;
- } php_iconv_stream_filter;
- /* }}} iconv stream filter */
- /* {{{ php_iconv_stream_filter_dtor */
- static void php_iconv_stream_filter_dtor(php_iconv_stream_filter *self)
- {
- iconv_close(self->cd);
- pefree(self->to_charset, self->persistent);
- pefree(self->from_charset, self->persistent);
- }
- /* }}} */
- /* {{{ php_iconv_stream_filter_ctor() */
- static php_iconv_err_t php_iconv_stream_filter_ctor(php_iconv_stream_filter *self,
- const char *to_charset, size_t to_charset_len,
- const char *from_charset, size_t from_charset_len, int persistent)
- {
- if (NULL == (self->to_charset = pemalloc(to_charset_len + 1, persistent))) {
- return PHP_ICONV_ERR_ALLOC;
- }
- self->to_charset_len = to_charset_len;
- if (NULL == (self->from_charset = pemalloc(from_charset_len + 1, persistent))) {
- pefree(self->to_charset, persistent);
- return PHP_ICONV_ERR_ALLOC;
- }
- self->from_charset_len = from_charset_len;
- memcpy(self->to_charset, to_charset, to_charset_len);
- self->to_charset[to_charset_len] = '\0';
- memcpy(self->from_charset, from_charset, from_charset_len);
- self->from_charset[from_charset_len] = '\0';
- if ((iconv_t)-1 == (self->cd = iconv_open(self->to_charset, self->from_charset))) {
- pefree(self->from_charset, persistent);
- pefree(self->to_charset, persistent);
- return PHP_ICONV_ERR_UNKNOWN;
- }
- self->persistent = persistent;
- self->stub_len = 0;
- return PHP_ICONV_ERR_SUCCESS;
- }
- /* }}} */
- /* {{{ php_iconv_stream_filter_append_bucket */
- static int php_iconv_stream_filter_append_bucket(
- php_iconv_stream_filter *self,
- php_stream *stream, php_stream_filter *filter,
- php_stream_bucket_brigade *buckets_out,
- const char *ps, size_t buf_len, size_t *consumed,
- int persistent TSRMLS_DC)
- {
- php_stream_bucket *new_bucket;
- char *out_buf = NULL;
- size_t out_buf_size;
- char *pd, *pt;
- size_t ocnt, prev_ocnt, icnt, tcnt;
- size_t initial_out_buf_size;
- if (ps == NULL) {
- initial_out_buf_size = 64;
- icnt = 1;
- } else {
- initial_out_buf_size = buf_len;
- icnt = buf_len;
- }
- out_buf_size = ocnt = prev_ocnt = initial_out_buf_size;
- if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
- return FAILURE;
- }
- pd = out_buf;
- if (self->stub_len > 0) {
- pt = self->stub;
- tcnt = self->stub_len;
- while (tcnt > 0) {
- if (iconv(self->cd, &pt, &tcnt, &pd, &ocnt) == (size_t)-1) {
- #if ICONV_SUPPORTS_ERRNO
- switch (errno) {
- case EILSEQ:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset);
- goto out_failure;
- case EINVAL:
- if (ps != NULL) {
- if (icnt > 0) {
- if (self->stub_len >= sizeof(self->stub)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): insufficient buffer", self->from_charset, self->to_charset);
- goto out_failure;
- }
- self->stub[self->stub_len++] = *(ps++);
- icnt--;
- pt = self->stub;
- tcnt = self->stub_len;
- } else {
- tcnt = 0;
- break;
- }
- } else {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset);
- goto out_failure;
- }
- break;
- case E2BIG: {
- char *new_out_buf;
- size_t new_out_buf_size;
- new_out_buf_size = out_buf_size << 1;
- if (new_out_buf_size < out_buf_size) {
- /* whoa! no bigger buckets are sold anywhere... */
- if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
- goto out_failure;
- }
- php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
- out_buf_size = ocnt = initial_out_buf_size;
- if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
- return FAILURE;
- }
- pd = out_buf;
- } else {
- if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
- if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
- goto out_failure;
- }
- php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
- return FAILURE;
- }
- pd = new_out_buf + (pd - out_buf);
- ocnt += (new_out_buf_size - out_buf_size);
- out_buf = new_out_buf;
- out_buf_size = new_out_buf_size;
- }
- } break;
- default:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
- goto out_failure;
- }
- #else
- if (ocnt == prev_ocnt) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
- goto out_failure;
- }
- #endif
- }
- prev_ocnt = ocnt;
- }
- memmove(self->stub, pt, tcnt);
- self->stub_len = tcnt;
- }
- while (icnt > 0) {
- if ((ps == NULL ? iconv(self->cd, NULL, NULL, &pd, &ocnt):
- iconv(self->cd, (char **)&ps, &icnt, &pd, &ocnt)) == (size_t)-1) {
- #if ICONV_SUPPORTS_ERRNO
- switch (errno) {
- case EILSEQ:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset);
- goto out_failure;
- case EINVAL:
- if (ps != NULL) {
- if (icnt > sizeof(self->stub)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): insufficient buffer", self->from_charset, self->to_charset);
- goto out_failure;
- }
- memcpy(self->stub, ps, icnt);
- self->stub_len = icnt;
- ps += icnt;
- icnt = 0;
- } else {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unexpected octet values", self->from_charset, self->to_charset);
- goto out_failure;
- }
- break;
- case E2BIG: {
- char *new_out_buf;
- size_t new_out_buf_size;
- new_out_buf_size = out_buf_size << 1;
- if (new_out_buf_size < out_buf_size) {
- /* whoa! no bigger buckets are sold anywhere... */
- if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
- goto out_failure;
- }
- php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
- out_buf_size = ocnt = initial_out_buf_size;
- if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
- return FAILURE;
- }
- pd = out_buf;
- } else {
- if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
- if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
- goto out_failure;
- }
- php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
- return FAILURE;
- }
- pd = new_out_buf + (pd - out_buf);
- ocnt += (new_out_buf_size - out_buf_size);
- out_buf = new_out_buf;
- out_buf_size = new_out_buf_size;
- }
- } break;
- default:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
- goto out_failure;
- }
- #else
- if (ocnt == prev_ocnt) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): unknown error", self->from_charset, self->to_charset);
- goto out_failure;
- }
- #endif
- } else {
- if (ps == NULL) {
- break;
- }
- }
- prev_ocnt = ocnt;
- }
- if (out_buf_size - ocnt > 0) {
- if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
- goto out_failure;
- }
- php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
- } else {
- pefree(out_buf, persistent);
- }
- *consumed += buf_len - icnt;
- return SUCCESS;
- out_failure:
- pefree(out_buf, persistent);
- return FAILURE;
- }
- /* }}} php_iconv_stream_filter_append_bucket */
- /* {{{ php_iconv_stream_filter_do_filter */
- static php_stream_filter_status_t php_iconv_stream_filter_do_filter(
- php_stream *stream, php_stream_filter *filter,
- php_stream_bucket_brigade *buckets_in,
- php_stream_bucket_brigade *buckets_out,
- size_t *bytes_consumed, int flags TSRMLS_DC)
- {
- php_stream_bucket *bucket = NULL;
- size_t consumed = 0;
- php_iconv_stream_filter *self = (php_iconv_stream_filter *)filter->abstract;
- while (buckets_in->head != NULL) {
- bucket = buckets_in->head;
- php_stream_bucket_unlink(bucket TSRMLS_CC);
- if (php_iconv_stream_filter_append_bucket(self, stream, filter,
- buckets_out, bucket->buf, bucket->buflen, &consumed,
- php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
- goto out_failure;
- }
- php_stream_bucket_delref(bucket TSRMLS_CC);
- }
- if (flags != PSFS_FLAG_NORMAL) {
- if (php_iconv_stream_filter_append_bucket(self, stream, filter,
- buckets_out, NULL, 0, &consumed,
- php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
- goto out_failure;
- }
- }
- if (bytes_consumed != NULL) {
- *bytes_consumed = consumed;
- }
- return PSFS_PASS_ON;
- out_failure:
- if (bucket != NULL) {
- php_stream_bucket_delref(bucket TSRMLS_CC);
- }
- return PSFS_ERR_FATAL;
- }
- /* }}} */
- /* {{{ php_iconv_stream_filter_cleanup */
- static void php_iconv_stream_filter_cleanup(php_stream_filter *filter TSRMLS_DC)
- {
- php_iconv_stream_filter_dtor((php_iconv_stream_filter *)filter->abstract);
- pefree(filter->abstract, ((php_iconv_stream_filter *)filter->abstract)->persistent);
- }
- /* }}} */
- static php_stream_filter_ops php_iconv_stream_filter_ops = {
- php_iconv_stream_filter_do_filter,
- php_iconv_stream_filter_cleanup,
- "convert.iconv.*"
- };
- /* {{{ php_iconv_stream_filter_create */
- static php_stream_filter *php_iconv_stream_filter_factory_create(const char *name, zval *params, int persistent TSRMLS_DC)
- {
- php_stream_filter *retval = NULL;
- php_iconv_stream_filter *inst;
- char *from_charset = NULL, *to_charset = NULL;
- size_t from_charset_len, to_charset_len;
- if ((from_charset = strchr(name, '.')) == NULL) {
- return NULL;
- }
- ++from_charset;
- if ((from_charset = strchr(from_charset, '.')) == NULL) {
- return NULL;
- }
- ++from_charset;
- if ((to_charset = strpbrk(from_charset, "/.")) == NULL) {
- return NULL;
- }
- from_charset_len = to_charset - from_charset;
- ++to_charset;
- to_charset_len = strlen(to_charset);
- if (from_charset_len >= ICONV_CSNMAXLEN || to_charset_len >= ICONV_CSNMAXLEN) {
- return NULL;
- }
- if (NULL == (inst = pemalloc(sizeof(php_iconv_stream_filter), persistent))) {
- return NULL;
- }
- if (php_iconv_stream_filter_ctor(inst, to_charset, to_charset_len, from_charset, from_charset_len, persistent) != PHP_ICONV_ERR_SUCCESS) {
- pefree(inst, persistent);
- return NULL;
- }
- if (NULL == (retval = php_stream_filter_alloc(&php_iconv_stream_filter_ops, inst, persistent))) {
- php_iconv_stream_filter_dtor(inst);
- pefree(inst, persistent);
- }
- return retval;
- }
- /* }}} */
- /* {{{ php_iconv_stream_register_factory */
- static php_iconv_err_t php_iconv_stream_filter_register_factory(TSRMLS_D)
- {
- static php_stream_filter_factory filter_factory = {
- php_iconv_stream_filter_factory_create
- };
- if (FAILURE == php_stream_filter_register_factory(
- php_iconv_stream_filter_ops.label,
- &filter_factory TSRMLS_CC)) {
- return PHP_ICONV_ERR_UNKNOWN;
- }
- return PHP_ICONV_ERR_SUCCESS;
- }
- /* }}} */
- /* {{{ php_iconv_stream_unregister_factory */
- static php_iconv_err_t php_iconv_stream_filter_unregister_factory(TSRMLS_D)
- {
- if (FAILURE == php_stream_filter_unregister_factory(
- php_iconv_stream_filter_ops.label TSRMLS_CC)) {
- return PHP_ICONV_ERR_UNKNOWN;
- }
- return PHP_ICONV_ERR_SUCCESS;
- }
- /* }}} */
- /* }}} */
- #endif
- /*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
- */
|