File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard / iptc.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:03:57 2014 UTC (10 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2014 The PHP Group                                |
    6:    +----------------------------------------------------------------------+
    7:    | This source file is subject to version 3.01 of the PHP license,      |
    8:    | that is bundled with this package in the file LICENSE, and is        |
    9:    | available through the world-wide-web at the following url:           |
   10:    | http://www.php.net/license/3_01.txt                                  |
   11:    | If you did not receive a copy of the PHP license and are unable to   |
   12:    | obtain it through the world-wide-web, please send a note to          |
   13:    | license@php.net so we can mail you a copy immediately.               |
   14:    +----------------------------------------------------------------------+
   15:    | Author: Thies C. Arntzen <thies@thieso.net>                          |
   16:    +----------------------------------------------------------------------+
   17:  */
   18: 
   19: /* $Id: iptc.c,v 1.1.1.4 2014/06/15 20:03:57 misho Exp $ */
   20: 
   21: /*
   22:  * Functions to parse & compse IPTC data.
   23:  * PhotoShop >= 3.0 can read and write textual data to JPEG files.
   24:  * ... more to come .....
   25:  * 
   26:  * i know, parts of this is now duplicated in image.c 
   27:  * but in this case i think it's okay!
   28:  */
   29: 
   30: /*
   31:  * TODO:
   32:  *  - add IPTC translation table
   33:  */
   34:  
   35: #include "php.h"
   36: #include "php_iptc.h"
   37: #include "ext/standard/head.h"
   38: 
   39: #include <sys/stat.h>
   40: 
   41: 
   42: /* some defines for the different JPEG block types */
   43: #define M_SOF0  0xC0            /* Start Of Frame N */
   44: #define M_SOF1  0xC1            /* N indicates which compression process */
   45: #define M_SOF2  0xC2            /* Only SOF0-SOF2 are now in common use */
   46: #define M_SOF3  0xC3
   47: #define M_SOF5  0xC5            /* NB: codes C4 and CC are NOT SOF markers */
   48: #define M_SOF6  0xC6
   49: #define M_SOF7  0xC7
   50: #define M_SOF9  0xC9
   51: #define M_SOF10 0xCA
   52: #define M_SOF11 0xCB
   53: #define M_SOF13 0xCD
   54: #define M_SOF14 0xCE
   55: #define M_SOF15 0xCF
   56: #define M_SOI   0xD8
   57: #define M_EOI   0xD9            /* End Of Image (end of datastream) */
   58: #define M_SOS   0xDA            /* Start Of Scan (begins compressed data) */
   59: #define M_APP0  0xe0
   60: #define M_APP1  0xe1
   61: #define M_APP2  0xe2
   62: #define M_APP3  0xe3
   63: #define M_APP4  0xe4
   64: #define M_APP5  0xe5
   65: #define M_APP6  0xe6
   66: #define M_APP7  0xe7
   67: #define M_APP8  0xe8
   68: #define M_APP9  0xe9
   69: #define M_APP10 0xea
   70: #define M_APP11 0xeb
   71: #define M_APP12 0xec
   72: #define M_APP13 0xed
   73: #define M_APP14 0xee
   74: #define M_APP15 0xef
   75: 
   76: /* {{{ php_iptc_put1
   77:  */
   78: static int php_iptc_put1(FILE *fp, int spool, unsigned char c, unsigned char **spoolbuf TSRMLS_DC)
   79: { 
   80: 	if (spool > 0)
   81: 		PUTC(c);
   82: 
   83: 	if (spoolbuf) *(*spoolbuf)++ = c;
   84: 
   85:   	return c;
   86: }
   87: /* }}} */
   88: 
   89: /* {{{ php_iptc_get1
   90:  */
   91: static int php_iptc_get1(FILE *fp, int spool, unsigned char **spoolbuf TSRMLS_DC)
   92: { 	
   93: 	int c;
   94: 	char cc;
   95: 
   96: 	c = getc(fp);
   97: 
   98: 	if (c == EOF) return EOF;
   99: 
  100: 	if (spool > 0) {
  101: 		cc = c;
  102: 		PUTC(cc);
  103: 	}
  104: 
  105: 	if (spoolbuf) *(*spoolbuf)++ = c;
  106: 
  107: 	return c;
  108: }
  109: /* }}} */
  110: 
  111: /* {{{ php_iptc_read_remaining
  112:  */
  113: static int php_iptc_read_remaining(FILE *fp, int spool, unsigned char **spoolbuf TSRMLS_DC)
  114: {
  115:   	while (php_iptc_get1(fp, spool, spoolbuf TSRMLS_CC) != EOF) continue;
  116: 
  117: 	return M_EOI;
  118: }
  119: /* }}} */
  120: 
  121: /* {{{ php_iptc_skip_variable
  122:  */
  123: static int php_iptc_skip_variable(FILE *fp, int spool, unsigned char **spoolbuf TSRMLS_DC)
  124: { 
  125: 	unsigned int  length;
  126: 	int c1, c2;
  127: 
  128:     if ((c1 = php_iptc_get1(fp, spool, spoolbuf TSRMLS_CC)) == EOF) return M_EOI;
  129: 
  130:     if ((c2 = php_iptc_get1(fp, spool, spoolbuf TSRMLS_CC)) == EOF) return M_EOI;
  131: 
  132: 	length = (((unsigned char) c1) << 8) + ((unsigned char) c2);
  133: 
  134: 	length -= 2;
  135: 
  136: 	while (length--)
  137: 		if (php_iptc_get1(fp, spool, spoolbuf TSRMLS_CC) == EOF) return M_EOI;
  138: 
  139: 	return 0;
  140: }
  141: /* }}} */
  142: 
  143: /* {{{ php_iptc_next_marker
  144:  */
  145: static int php_iptc_next_marker(FILE *fp, int spool, unsigned char **spoolbuf TSRMLS_DC)
  146: {
  147:     int c;
  148: 
  149:     /* skip unimportant stuff */
  150: 
  151:     c = php_iptc_get1(fp, spool, spoolbuf TSRMLS_CC);
  152: 
  153: 	if (c == EOF) return M_EOI;
  154: 
  155:     while (c != 0xff) {
  156:         if ((c = php_iptc_get1(fp, spool, spoolbuf TSRMLS_CC)) == EOF)
  157:             return M_EOI; /* we hit EOF */
  158:     }
  159: 
  160:     /* get marker byte, swallowing possible padding */
  161:     do {
  162:         c = php_iptc_get1(fp, 0, 0 TSRMLS_CC);
  163: 		if (c == EOF)
  164:             return M_EOI;       /* we hit EOF */
  165: 		else
  166: 		if (c == 0xff)
  167: 			php_iptc_put1(fp, spool, (unsigned char)c, spoolbuf TSRMLS_CC);
  168:     } while (c == 0xff);
  169: 
  170:     return (unsigned int) c;
  171: }
  172: /* }}} */
  173: 
  174: static char psheader[] = "\xFF\xED\0\0Photoshop 3.0\08BIM\x04\x04\0\0\0\0";
  175: 
  176: /* {{{ proto array iptcembed(string iptcdata, string jpeg_file_name [, int spool])
  177:    Embed binary IPTC data into a JPEG image. */
  178: PHP_FUNCTION(iptcembed)
  179: {
  180: 	char *iptcdata, *jpeg_file;
  181: 	int iptcdata_len, jpeg_file_len;
  182: 	long spool = 0;
  183: 	FILE *fp;
  184: 	unsigned int marker, done = 0;
  185: 	int inx;
  186: 	unsigned char *spoolbuf = NULL, *poi = NULL;
  187: 	struct stat sb;
  188: 	zend_bool written = 0;
  189: 
  190: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sp|l", &iptcdata, &iptcdata_len, &jpeg_file, &jpeg_file_len, &spool) != SUCCESS) {
  191: 		return;
  192: 	}
  193: 
  194: 	if (php_check_open_basedir(jpeg_file TSRMLS_CC)) {
  195: 		RETURN_FALSE;
  196: 	}
  197: 
  198: 	if ((fp = VCWD_FOPEN(jpeg_file, "rb")) == 0) {
  199: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open %s", jpeg_file);
  200: 		RETURN_FALSE;
  201: 	}
  202: 
  203: 	if (spool < 2) {
  204: 		fstat(fileno(fp), &sb);
  205: 
  206: 		poi = spoolbuf = safe_emalloc(1, iptcdata_len + sizeof(psheader) + sb.st_size + 1024, 1);
  207: 		memset(poi, 0, iptcdata_len + sizeof(psheader) + sb.st_size + 1024 + 1);
  208: 	} 
  209: 
  210: 	if (php_iptc_get1(fp, spool, poi?&poi:0 TSRMLS_CC) != 0xFF) {
  211: 		fclose(fp);
  212: 		if (spoolbuf) {
  213: 			efree(spoolbuf);
  214: 		}
  215: 		RETURN_FALSE;
  216: 	}
  217: 
  218: 	if (php_iptc_get1(fp, spool, poi?&poi:0 TSRMLS_CC) != 0xD8) {
  219: 		fclose(fp);
  220: 		if (spoolbuf) {
  221: 			efree(spoolbuf);
  222: 		}
  223: 		RETURN_FALSE;
  224: 	}
  225: 
  226: 	while (!done) {
  227: 		marker = php_iptc_next_marker(fp, spool, poi?&poi:0 TSRMLS_CC);
  228: 
  229: 		if (marker == M_EOI) { /* EOF */
  230: 			break;
  231: 		} else if (marker != M_APP13) { 
  232: 			php_iptc_put1(fp, spool, (unsigned char)marker, poi?&poi:0 TSRMLS_CC);
  233: 		}
  234: 
  235: 		switch (marker) {
  236: 			case M_APP13:
  237: 				/* we are going to write a new APP13 marker, so don't output the old one */
  238: 				php_iptc_skip_variable(fp, 0, 0 TSRMLS_CC);    
  239: 				php_iptc_read_remaining(fp, spool, poi?&poi:0 TSRMLS_CC);
  240: 				done = 1;
  241: 				break;
  242: 
  243: 			case M_APP0:
  244: 				/* APP0 is in each and every JPEG, so when we hit APP0 we insert our new APP13! */
  245: 			case M_APP1:
  246: 				if (written) {
  247: 					/* don't try to write the data twice */
  248: 					break;
  249: 				}
  250: 				written = 1;
  251: 
  252: 				php_iptc_skip_variable(fp, spool, poi?&poi:0 TSRMLS_CC);
  253: 
  254: 				if (iptcdata_len & 1) {
  255: 					iptcdata_len++; /* make the length even */
  256: 				}
  257: 
  258: 				psheader[ 2 ] = (iptcdata_len+28)>>8;
  259: 				psheader[ 3 ] = (iptcdata_len+28)&0xff;
  260: 
  261: 				for (inx = 0; inx < 28; inx++) {
  262: 					php_iptc_put1(fp, spool, psheader[inx], poi?&poi:0 TSRMLS_CC);
  263: 				}
  264: 
  265: 				php_iptc_put1(fp, spool, (unsigned char)(iptcdata_len>>8), poi?&poi:0 TSRMLS_CC);
  266: 				php_iptc_put1(fp, spool, (unsigned char)(iptcdata_len&0xff), poi?&poi:0 TSRMLS_CC);
  267: 
  268: 				for (inx = 0; inx < iptcdata_len; inx++) {
  269: 					php_iptc_put1(fp, spool, iptcdata[inx], poi?&poi:0 TSRMLS_CC);
  270: 				}
  271: 				break;
  272: 
  273: 			case M_SOS:								
  274: 				/* we hit data, no more marker-inserting can be done! */
  275: 				php_iptc_read_remaining(fp, spool, poi?&poi:0 TSRMLS_CC);
  276: 				done = 1;
  277: 				break;
  278: 
  279: 			default:
  280: 				php_iptc_skip_variable(fp, spool, poi?&poi:0 TSRMLS_CC);
  281: 				break;
  282: 		}
  283: 	}
  284: 
  285: 	fclose(fp);
  286: 
  287: 	if (spool < 2) {
  288: 		RETVAL_STRINGL(spoolbuf, poi - spoolbuf, 0);
  289: 	} else {
  290: 		RETURN_TRUE;
  291: 	}
  292: }
  293: /* }}} */
  294: 
  295: /* {{{ proto array iptcparse(string iptcdata)
  296:    Parse binary IPTC-data into associative array */
  297: PHP_FUNCTION(iptcparse)
  298: {
  299: 	int inx = 0, len;
  300: 	unsigned int tagsfound = 0;
  301: 	unsigned char *buffer, recnum, dataset, key[ 16 ];
  302: 	char *str;
  303: 	int str_len;
  304: 	zval *values, **element;
  305: 
  306: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) != SUCCESS) {
  307: 		return;
  308: 	}
  309: 
  310: 	buffer = (unsigned char *)str;
  311: 
  312: 	while (inx < str_len) { /* find 1st tag */
  313: 		if ((buffer[inx] == 0x1c) && ((buffer[inx+1] == 0x01) || (buffer[inx+1] == 0x02))){ 
  314: 			break;
  315: 		} else {
  316: 			inx++;
  317: 		}
  318: 	}
  319: 
  320: 	while (inx < str_len) {
  321: 		if (buffer[ inx++ ] != 0x1c) {
  322: 			break;   /* we ran against some data which does not conform to IPTC - stop parsing! */
  323: 		} 
  324: 		
  325: 		if ((inx + 4) >= str_len)
  326: 			break;
  327: 
  328: 		dataset = buffer[ inx++ ];
  329: 		recnum = buffer[ inx++ ];
  330: 
  331: 		if (buffer[ inx ] & (unsigned char) 0x80) { /* long tag */
  332: 			if((inx+6) >= str_len) {
  333: 				break;
  334: 			}
  335: 			len = (((long) buffer[ inx + 2 ]) << 24) + (((long) buffer[ inx + 3 ]) << 16) + 
  336: 				  (((long) buffer[ inx + 4 ]) <<  8) + (((long) buffer[ inx + 5 ]));
  337: 			inx += 6;
  338: 		} else { /* short tag */
  339: 			len = (((unsigned short) buffer[ inx ])<<8) | (unsigned short)buffer[ inx+1 ];
  340: 			inx += 2;
  341: 		}
  342: 		
  343: 		if ((len < 0) || (len > str_len) || (inx + len) > str_len) {
  344: 			break;
  345: 		}
  346: 
  347: 		snprintf(key, sizeof(key), "%d#%03d", (unsigned int) dataset, (unsigned int) recnum);
  348: 
  349: 		if (tagsfound == 0) { /* found the 1st tag - initialize the return array */
  350: 			array_init(return_value);
  351: 		}
  352: 
  353: 		if (zend_hash_find(Z_ARRVAL_P(return_value), key, strlen(key) + 1, (void **) &element) == FAILURE) {
  354: 			MAKE_STD_ZVAL(values);
  355: 			array_init(values);
  356: 			
  357: 			zend_hash_update(Z_ARRVAL_P(return_value), key, strlen(key) + 1, (void *) &values, sizeof(zval*), (void **) &element);
  358: 		} 
  359: 			
  360: 		add_next_index_stringl(*element, buffer+inx, len, 1);
  361: 		inx += len;
  362: 		tagsfound++;
  363: 	}
  364: 
  365: 	if (! tagsfound) {
  366: 		RETURN_FALSE;
  367: 	}
  368: }
  369: /* }}} */
  370: 
  371: /*
  372:  * Local variables:
  373:  * tab-width: 4
  374:  * c-basic-offset: 4
  375:  * End:
  376:  * vim600: sw=4 ts=4 fdm=marker
  377:  * vim<600: sw=4 ts=4
  378:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>