Annotation of embedaddon/php/ext/standard/iptc.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1997-2012 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 321634 2012-01-01 13:15:04Z felipe $ */
! 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, inx;
! 185: unsigned char *spoolbuf = NULL, *poi = NULL;
! 186: struct stat sb;
! 187: zend_bool written = 0;
! 188:
! 189: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &iptcdata, &iptcdata_len, &jpeg_file, &jpeg_file_len, &spool) != SUCCESS) {
! 190: return;
! 191: }
! 192:
! 193: if (strlen(jpeg_file) != jpeg_file_len) {
! 194: RETURN_FALSE;
! 195: }
! 196:
! 197: if (PG(safe_mode) && (!php_checkuid(jpeg_file, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
! 198: RETURN_FALSE;
! 199: }
! 200:
! 201: if (php_check_open_basedir(jpeg_file TSRMLS_CC)) {
! 202: RETURN_FALSE;
! 203: }
! 204:
! 205: if ((fp = VCWD_FOPEN(jpeg_file, "rb")) == 0) {
! 206: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open %s", jpeg_file);
! 207: RETURN_FALSE;
! 208: }
! 209:
! 210: if (spool < 2) {
! 211: fstat(fileno(fp), &sb);
! 212:
! 213: poi = spoolbuf = safe_emalloc(1, iptcdata_len + sizeof(psheader) + sb.st_size + 1024, 1);
! 214: memset(poi, 0, iptcdata_len + sizeof(psheader) + sb.st_size + 1024 + 1);
! 215: }
! 216:
! 217: if (php_iptc_get1(fp, spool, poi?&poi:0 TSRMLS_CC) != 0xFF) {
! 218: fclose(fp);
! 219: if (spoolbuf) {
! 220: efree(spoolbuf);
! 221: }
! 222: RETURN_FALSE;
! 223: }
! 224:
! 225: if (php_iptc_get1(fp, spool, poi?&poi:0 TSRMLS_CC) != 0xD8) {
! 226: fclose(fp);
! 227: if (spoolbuf) {
! 228: efree(spoolbuf);
! 229: }
! 230: RETURN_FALSE;
! 231: }
! 232:
! 233: while (!done) {
! 234: marker = php_iptc_next_marker(fp, spool, poi?&poi:0 TSRMLS_CC);
! 235:
! 236: if (marker == M_EOI) { /* EOF */
! 237: break;
! 238: } else if (marker != M_APP13) {
! 239: php_iptc_put1(fp, spool, (unsigned char)marker, poi?&poi:0 TSRMLS_CC);
! 240: }
! 241:
! 242: switch (marker) {
! 243: case M_APP13:
! 244: /* we are going to write a new APP13 marker, so don't output the old one */
! 245: php_iptc_skip_variable(fp, 0, 0 TSRMLS_CC);
! 246: php_iptc_read_remaining(fp, spool, poi?&poi:0 TSRMLS_CC);
! 247: done = 1;
! 248: break;
! 249:
! 250: case M_APP0:
! 251: /* APP0 is in each and every JPEG, so when we hit APP0 we insert our new APP13! */
! 252: case M_APP1:
! 253: if (written) {
! 254: /* don't try to write the data twice */
! 255: break;
! 256: }
! 257: written = 1;
! 258:
! 259: php_iptc_skip_variable(fp, spool, poi?&poi:0 TSRMLS_CC);
! 260:
! 261: if (iptcdata_len & 1) {
! 262: iptcdata_len++; /* make the length even */
! 263: }
! 264:
! 265: psheader[ 2 ] = (iptcdata_len+28)>>8;
! 266: psheader[ 3 ] = (iptcdata_len+28)&0xff;
! 267:
! 268: for (inx = 0; inx < 28; inx++) {
! 269: php_iptc_put1(fp, spool, psheader[inx], poi?&poi:0 TSRMLS_CC);
! 270: }
! 271:
! 272: php_iptc_put1(fp, spool, (unsigned char)(iptcdata_len>>8), poi?&poi:0 TSRMLS_CC);
! 273: php_iptc_put1(fp, spool, (unsigned char)(iptcdata_len&0xff), poi?&poi:0 TSRMLS_CC);
! 274:
! 275: for (inx = 0; inx < iptcdata_len; inx++) {
! 276: php_iptc_put1(fp, spool, iptcdata[inx], poi?&poi:0 TSRMLS_CC);
! 277: }
! 278: break;
! 279:
! 280: case M_SOS:
! 281: /* we hit data, no more marker-inserting can be done! */
! 282: php_iptc_read_remaining(fp, spool, poi?&poi:0 TSRMLS_CC);
! 283: done = 1;
! 284: break;
! 285:
! 286: default:
! 287: php_iptc_skip_variable(fp, spool, poi?&poi:0 TSRMLS_CC);
! 288: break;
! 289: }
! 290: }
! 291:
! 292: fclose(fp);
! 293:
! 294: if (spool < 2) {
! 295: RETVAL_STRINGL(spoolbuf, poi - spoolbuf, 0);
! 296: } else {
! 297: RETURN_TRUE;
! 298: }
! 299: }
! 300: /* }}} */
! 301:
! 302: /* {{{ proto array iptcparse(string iptcdata)
! 303: Parse binary IPTC-data into associative array */
! 304: PHP_FUNCTION(iptcparse)
! 305: {
! 306: unsigned int inx = 0, len, tagsfound = 0;
! 307: unsigned char *buffer, recnum, dataset, key[ 16 ];
! 308: char *str;
! 309: int str_len;
! 310: zval *values, **element;
! 311:
! 312: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) != SUCCESS) {
! 313: return;
! 314: }
! 315:
! 316: buffer = (unsigned char *)str;
! 317:
! 318: while (inx < str_len) { /* find 1st tag */
! 319: if ((buffer[inx] == 0x1c) && ((buffer[inx+1] == 0x01) || (buffer[inx+1] == 0x02))){
! 320: break;
! 321: } else {
! 322: inx++;
! 323: }
! 324: }
! 325:
! 326: while (inx < str_len) {
! 327: if (buffer[ inx++ ] != 0x1c) {
! 328: break; /* we ran against some data which does not conform to IPTC - stop parsing! */
! 329: }
! 330:
! 331: if ((inx + 4) >= str_len)
! 332: break;
! 333:
! 334: dataset = buffer[ inx++ ];
! 335: recnum = buffer[ inx++ ];
! 336:
! 337: if (buffer[ inx ] & (unsigned char) 0x80) { /* long tag */
! 338: len = (((long) buffer[ inx + 2 ]) << 24) + (((long) buffer[ inx + 3 ]) << 16) +
! 339: (((long) buffer[ inx + 4 ]) << 8) + (((long) buffer[ inx + 5 ]));
! 340: inx += 6;
! 341: } else { /* short tag */
! 342: len = (((unsigned short) buffer[ inx ])<<8) | (unsigned short)buffer[ inx+1 ];
! 343: inx += 2;
! 344: }
! 345:
! 346: snprintf(key, sizeof(key), "%d#%03d", (unsigned int) dataset, (unsigned int) recnum);
! 347:
! 348: if ((len > str_len) || (inx + len) > str_len) {
! 349: break;
! 350: }
! 351:
! 352: if (tagsfound == 0) { /* found the 1st tag - initialize the return array */
! 353: array_init(return_value);
! 354: }
! 355:
! 356: if (zend_hash_find(Z_ARRVAL_P(return_value), key, strlen(key) + 1, (void **) &element) == FAILURE) {
! 357: MAKE_STD_ZVAL(values);
! 358: array_init(values);
! 359:
! 360: zend_hash_update(Z_ARRVAL_P(return_value), key, strlen(key) + 1, (void *) &values, sizeof(zval*), (void **) &element);
! 361: }
! 362:
! 363: add_next_index_stringl(*element, buffer+inx, len, 1);
! 364: inx += len;
! 365: tagsfound++;
! 366: }
! 367:
! 368: if (! tagsfound) {
! 369: RETURN_FALSE;
! 370: }
! 371: }
! 372: /* }}} */
! 373:
! 374: /*
! 375: * Local variables:
! 376: * tab-width: 4
! 377: * c-basic-offset: 4
! 378: * End:
! 379: * vim600: sw=4 ts=4 fdm=marker
! 380: * vim<600: sw=4 ts=4
! 381: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>