22 +----------------------------------------------------------------------+
33 | PHP HTML Embedded Scripting Language Version 3.0 |
44 +----------------------------------------------------------------------+
5- | Copyright (c) 1997,1998 PHP Development Team (See Credits file) |
5+ | Copyright (c) 1997-1999 PHP Development Team (See Credits file) |
66 +----------------------------------------------------------------------+
77 | This program is free software; you can redistribute it and/or modify |
88 | it under the terms of one of the following licenses: |
3333 * Functions to parse & compse IPTC data.
3434 * PhotoShop >= 3.0 can read and write textual data to JPEG files.
3535 * ... more to come .....
36+ *
37+ * i know, parts of this is now duplicated in image.c
38+ * but in this case i think it's okay!
3639 */
3740
3841/*
3942 * TODO:
4043 * - add IPTC translation table
41- * - implement a call to embed iptc into a JPEG file
4244 */
4345
4446#include "php.h"
4547#include "php3_iptc.h"
48+ #include "ext/standard/head.h"
4649
50+ #include <sys/stat.h>
51+
52+
53+ /* some defines for the different JPEG block types */
54+ #define M_SOF0 0xC0 /* Start Of Frame N */
55+ #define M_SOF1 0xC1 /* N indicates which compression process */
56+ #define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
57+ #define M_SOF3 0xC3
58+ #define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
59+ #define M_SOF6 0xC6
60+ #define M_SOF7 0xC7
61+ #define M_SOF9 0xC9
62+ #define M_SOF10 0xCA
63+ #define M_SOF11 0xCB
64+ #define M_SOF13 0xCD
65+ #define M_SOF14 0xCE
66+ #define M_SOF15 0xCF
67+ #define M_SOI 0xD8
68+ #define M_EOI 0xD9 /* End Of Image (end of datastream) */
69+ #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
70+ #define M_APP0 0xe0
71+ #define M_APP1 0xe1
72+ #define M_APP2 0xe2
73+ #define M_APP3 0xe3
74+ #define M_APP4 0xe4
75+ #define M_APP5 0xe5
76+ #define M_APP6 0xe6
77+ #define M_APP7 0xe7
78+ #define M_APP8 0xe8
79+ #define M_APP9 0xe9
80+ #define M_APP10 0xea
81+ #define M_APP11 0xeb
82+ #define M_APP12 0xec
83+ #define M_APP13 0xed
84+ #define M_APP14 0xee
85+ #define M_APP15 0xef
86+
87+ static int php3_iptc_put1 (FILE * fp ,int spool ,unsigned char c ,unsigned char * * spoolbuf )
88+ {
89+ if (spool > 0 )
90+ PUTC (c );
91+
92+ if (spoolbuf ) * (* spoolbuf )++ = c ;
93+
94+ return c ;
95+ }
96+
97+ static int php3_iptc_get1 (FILE * fp ,int spool ,unsigned char * * spoolbuf )
98+ {
99+ int c ;
100+ char cc ;
101+
102+ c = getc (fp );
103+
104+ if (c == EOF ) return EOF ;
105+
106+ if (spool > 0 ) {
107+ cc = c ;
108+ PUTC (cc );
109+ }
110+
111+ if (spoolbuf ) * (* spoolbuf )++ = c ;
112+
113+ return c ;
114+ }
115+
116+ static int php3_iptc_read_remaining (FILE * fp ,int spool ,unsigned char * * spoolbuf )
117+ {
118+ int c ;
119+
120+ while ((c = php3_iptc_get1 (fp ,spool ,spoolbuf )) != EOF ) continue ;
121+
122+ return M_EOI ;
123+ }
124+
125+ static int php3_iptc_skip_variable (FILE * fp ,int spool ,unsigned char * * spoolbuf )
126+ {
127+ unsigned int length ;
128+ int c1 ,c2 ;
129+
130+ if ((c1 = php3_iptc_get1 (fp ,spool ,spoolbuf )) == EOF ) return M_EOI ;
131+
132+ if ((c2 = php3_iptc_get1 (fp ,spool ,spoolbuf )) == EOF ) return M_EOI ;
133+
134+ length = (((unsigned char ) c1 ) << 8 ) + ((unsigned char ) c2 );
135+
136+ length -= 2 ;
137+
138+ while (length -- )
139+ if (php3_iptc_get1 (fp ,spool ,spoolbuf ) == EOF ) return M_EOI ;
140+
141+ return 0 ;
142+ }
143+
144+ static int php3_iptc_nextmarker (FILE * fp ,int spool ,unsigned char * * spoolbuf )
145+ {
146+ int c ;
147+
148+ /* skip unimportant stuff */
149+
150+ c = php3_iptc_get1 (fp ,spool ,spoolbuf );
151+
152+ if (c == EOF ) return M_EOI ;
153+
154+ while (c != 0xff ) {
155+ if ((c = php3_iptc_get1 (fp ,spool ,spoolbuf )) == EOF )
156+ return M_EOI ; /* we hit EOF */
157+ }
158+
159+ /* get marker byte, swallowing possible padding */
160+ do {
161+ c = php3_iptc_get1 (fp ,0 ,0 );
162+ if (c == EOF )
163+ return M_EOI ; /* we hit EOF */
164+ else
165+ if (c == 0xff )
166+ php3_iptc_put1 (fp ,spool ,(unsigned char )c ,spoolbuf );
167+ } while (c == 0xff );
168+
169+ return (unsigned int ) c ;
170+ }
171+
172+ static char psheader [] = "\xFF\xED\0\0Photoshop 3.0\08BIM\x04\x04\0\0\0\0" ;
173+
174+ /* {{{ proto array iptcembed(string iptcdata, string jpeg_file_name [ , int spool ])
175+ Embed binary IPTC data into a JPEG image. */
176+ PHP_FUNCTION (iptcembed )
177+ {
178+ pval * iptcdata , * jpeg_file , * spool_flag ;
179+ FILE * fp ;
180+ unsigned int marker ;
181+ unsigned int spool = 0 , done = 0 , inx , len ;
182+ unsigned char * spoolbuf = 0 ,* poi = 0 ;
183+ struct stat sb ;
184+
185+ switch (ARG_COUNT (ht )){
186+ case 3 :
187+ if (getParameters (ht , 3 , & iptcdata , & jpeg_file , & spool_flag ) == FAILURE ) {
188+ WRONG_PARAM_COUNT ;
189+ }
190+ convert_to_string (iptcdata );
191+ convert_to_string (jpeg_file );
192+ convert_to_long (spool_flag );
193+ spool = spool_flag -> value .lval ;
194+ break ;
195+
196+ case 2 :
197+ if (getParameters (ht , 2 , & iptcdata , & jpeg_file ) == FAILURE ) {
198+ WRONG_PARAM_COUNT ;
199+ }
200+ convert_to_string (iptcdata );
201+ convert_to_string (jpeg_file );
202+ break ;
203+
204+ default :
205+ WRONG_PARAM_COUNT ;
206+ break ;
207+ }
208+
209+ if (_php3_check_open_basedir (jpeg_file -> value .str .val ))
210+ RETURN_FALSE ;
211+
212+ if ((fp = fopen (jpeg_file -> value .str .val ,"rb" )) == 0 ) {
213+ php3_error (E_WARNING , "Unable to open %s" , jpeg_file -> value .str .val );
214+ RETURN_FALSE ;
215+ }
216+
217+ if (spool > 0 )
218+ if (!php3_header ()){ /* we got a HEAD request. */
219+ if (spool == 2 ){
220+ RETURN_TRUE ; /* we only wanted to spool - report success. */
221+ } else
222+ if (spool == 1 ) {
223+ spool = 0 ; /* we wanted the file to be spooled/returned, just return it */
224+ }
225+ }
226+
227+ len = iptcdata -> value .str .len ;
228+
229+ if (spool < 2 ) {
230+ fstat (fileno (fp ),& sb );
231+
232+ poi = spoolbuf = emalloc (len + 30 + sb .st_size );
233+
234+ if (! spoolbuf ) {
235+ fclose (fp );
236+ RETURN_FALSE ;
237+ }
238+ }
239+
240+ if (php3_iptc_get1 (fp ,spool ,poi ?& poi :0 ) != 0xFF ) {
241+ fclose (fp );
242+ RETURN_FALSE ;
243+ }
244+
245+ if (php3_iptc_get1 (fp ,spool ,poi ?& poi :0 ) != 0xD8 ) {
246+ fclose (fp );
247+ RETURN_FALSE ;
248+ }
249+
250+ while (!done ) {
251+ marker = php3_iptc_nextmarker (fp ,spool ,poi ?& poi :0 );
252+
253+ if (marker == M_EOI ) { /* EOF */
254+ break ;
255+ } else if (marker != M_APP13 ) {
256+ php3_iptc_put1 (fp ,spool ,(unsigned char )marker ,poi ?& poi :0 );
257+ }
258+
259+ switch (marker ) {
260+ case M_APP13 :
261+ /* we are going to write a new APP13 marker, so don't output the old one */
262+ php3_iptc_skip_variable (fp ,0 ,0 );
263+ php3_iptc_read_remaining (fp ,spool ,poi ?& poi :0 );
264+ done = 1 ;
265+ break ;
266+
267+ case M_APP0 :
268+ /* APP0 is in each and every JPEG, so when we hit APP0 we insert our new APP13! */
269+ php3_iptc_skip_variable (fp ,spool ,poi ?& poi :0 );
270+
271+ if (len & 1 ) len ++ ; /* make the length even */
272+
273+ psheader [ 2 ] = (len + 28 )>>8 ;
274+ psheader [ 3 ] = (len + 28 )& 0xff ;
275+
276+ for (inx = 0 ; inx < 28 ; inx ++ )
277+ php3_iptc_put1 (fp ,spool ,psheader [inx ],poi ?& poi :0 );
278+
279+ php3_iptc_put1 (fp ,spool ,(unsigned char )(len >>8 ),poi ?& poi :0 );
280+ php3_iptc_put1 (fp ,spool ,(unsigned char )(len & 0xff ),poi ?& poi :0 );
281+
282+ for (inx = 0 ; inx < len ; inx ++ )
283+ php3_iptc_put1 (fp ,spool ,iptcdata -> value .str .val [inx ],poi ?& poi :0 );
284+ break ;
285+
286+ case M_SOS :
287+ /* we hit data, no more marker-inserting can be done! */
288+ php3_iptc_read_remaining (fp ,spool ,poi ?& poi :0 );
289+ done = 1 ;
290+ break ;
291+
292+ default :
293+ php3_iptc_skip_variable (fp ,spool ,poi ?& poi :0 );
294+ break ;
295+ }
296+ }
297+
298+ fclose (fp );
299+
300+ if (spool < 2 ) {
301+ RETVAL_STRINGL (spoolbuf ,poi - spoolbuf ,0 );
302+ } else {
303+ RETURN_TRUE ;
304+ }
305+ }
306+
307+ /* {{{ proto array iptcparse(string iptcdata)
308+ Parse binary IPTC-data into associative array. */
47309PHP_FUNCTION (iptcparse )
48310{
49311 unsigned int length , inx , len , inheader , tagsfound ;
50312 unsigned char * buffer ;
51313 unsigned char recnum , dataset ;
52314 unsigned char key [ 16 ];
53- pval values , * str , * element ;
315+ pval * values , * str , * * element ;
54316
55317 if (ARG_COUNT (ht ) != 1 || getParameters (ht , 1 , & str ) == FAILURE ) {
56318 WRONG_PARAM_COUNT ;
57319 }
58320 convert_to_string (str );
59321
60-
61322 inx = 0 ;
62323 length = str -> value .str .len ;
63324 buffer = str -> value .str .val ;
64325
65326 inheader = 0 ; /* have we already found the IPTC-Header??? */
66327 tagsfound = 0 ; /* number of tags already found */
67328
68- while (inx < length ) {
69- if (buffer [ inx ++ ] != 0x1c ) { /* skip all junk */
70- if (inheader ) {
71- break ; /* we ran against some data which does not conform to IPTC - stop parsing! */
72- } else {
73- continue ;
74- }
329+ while (inx < length ) { /* find 1st tag */
330+ if ((buffer [inx ] == 0x1c ) && (buffer [inx + 1 ] == 0x02 )){
331+ break ;
75332 } else {
76- inheader = 1 ;
333+ inx ++ ;
77334 }
335+ }
336+
337+ while (inx < length ) {
338+ if (buffer [ inx ++ ] != 0x1c ) {
339+ break ; /* we ran against some data which does not conform to IPTC - stop parsing! */
340+ }
78341
79342 if ((inx + 4 ) >= length )
80343 break ;
81344
82345 dataset = buffer [ inx ++ ];
83346 recnum = buffer [ inx ++ ];
84347
85- if (buffer [ inx ] & (unsigned char ) 0x80 ) {
348+ if (buffer [ inx ] & (unsigned char ) 0x80 ) { /* long tag */
86349 len = (((long ) buffer [ inx + 2 ]) << 24 ) + (((long ) buffer [ inx + 3 ]) << 16 ) +
87350 (((long ) buffer [ inx + 4 ]) << 8 ) + (((long ) buffer [ inx + 5 ]));
88351 inx += 6 ;
89- } else {
352+ } else { /* short tag */
90353 len = (((unsigned short ) buffer [ inx ])<<8 ) | (unsigned short )buffer [ inx + 1 ];
91354 inx += 2 ;
92355 }
@@ -104,15 +367,18 @@ PHP_FUNCTION(iptcparse)
104367 }
105368
106369 if (_php3_hash_find (return_value -> value .ht ,key ,strlen (key ) + 1 ,(void * * ) & element ) == FAILURE ) {
107- if (array_init (& values ) == FAILURE ) {
370+ values = emalloc (sizeof (pval ));
371+ values -> is_ref = 0 ;
372+ values -> refcount = 1 ;
373+ if (array_init (values ) == FAILURE ) {
108374 php3_error (E_ERROR , "Unable to initialize array" );
109375 RETURN_FALSE ;
110376 }
111377
112- _php3_hash_update (return_value -> value .ht , key , strlen (key )+ 1 , (void * ) & values , sizeof (pval ), (void * * ) & element );
378+ _php3_hash_update (return_value -> value .ht , key , strlen (key )+ 1 , (void * ) & values , sizeof (pval * ), (void * * ) & element );
113379 }
114380
115- add_next_index_stringl (element ,buffer + inx ,len ,1 );
381+ add_next_index_stringl (* element ,buffer + inx ,len ,1 );
116382
117383 inx += len ;
118384
@@ -123,6 +389,7 @@ PHP_FUNCTION(iptcparse)
123389 RETURN_FALSE ;
124390 }
125391}
392+ /* }}} */
126393
127394/*
128395 * Local variables:
0 commit comments