b679504529673a539747d75e23abf92a2ac801b8
[openjpeg.git] / src / bin / mj2 / meta_out.c
1 /* meta_out.c */
2 /* Dump MJ2, JP2 metadata (partial so far) to xml file */
3 /* Callable from mj2_to_metadata */
4 /* Contributed to Open JPEG by Glenn Pearson, contract software developer, U.S. National Library of Medicine.
5
6 The base code in this file was developed by the author as part of a video archiving
7 project for the U.S. National Library of Medicine, Bethesda, MD. 
8 It is the policy of NLM (and U.S. government) to not assert copyright.
9
10 A non-exclusive copy of this code has been contributed to the Open JPEG project.
11 Except for copyright, inclusion of the code within Open JPEG for distribution and use
12 can be bound by the Open JPEG open-source license and disclaimer, expressed elsewhere.
13 */
14
15 #include <windows.h> /* for time functions */
16
17 #include "opj_includes.h"
18 #include "mj2.h"
19
20 #include <time.h>
21 #include "meta_out.h"
22
23 static BOOL notes = TRUE;
24 static BOOL sampletables = FALSE;
25 static BOOL raw = TRUE;
26 static BOOL derived = TRUE;
27
28 opj_tcp_t *j2k_default_tcp;
29
30 /* Forwards */
31 int xml_write_overall_header(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr);
32 int xml_write_moov(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr);
33
34 void uint_to_chars(unsigned int value, char* buf);
35
36 void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum, unsigned int sampleframe, opj_event_mgr_t *event_mgr);
37 void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
38 void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
39 void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
40 void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum);
41
42 void UnixTimeToFileTime(time_t t, LPFILETIME pft);
43 void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst);
44 void xml_time_out(FILE* xmlout, time_t t);
45
46 void int16_to_3packedchars(short int value, char* buf);
47
48 void xml_write_moov_udta(FILE* xmlout, opj_mj2_t * movie);
49 void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie);
50 void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie);
51
52 int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int snum, opj_event_mgr_t *event_mgr);
53
54 void xml_out_frame_siz(FILE* xmlout, opj_image_t *img, opj_cp_t *cp);
55 void xml_out_frame_cod(FILE* xmlout, opj_tcp_t *tcp);
56 void xml_out_frame_coc(FILE* xmlout, opj_tcp_t *tcp, int numcomps); /* opj_image_t *img); */
57 BOOL same_component_style(opj_tccp_t *tccp1, opj_tccp_t *tccp2);
58 void xml_out_frame_qcd(FILE* xmlout, opj_tcp_t *tcp);
59 void xml_out_frame_qcc(FILE* xmlout, opj_tcp_t *tcp, int numcomps); /* opj_image_t *img); */
60 BOOL same_component_quantization(opj_tccp_t *tccp1, opj_tccp_t *tccp2);
61 void xml_out_frame_rgn(FILE* xmlout, opj_tcp_t *tcp, int numcomps);/* opj_image_t *img);*/
62 void xml_out_frame_poc(FILE* xmlout, opj_tcp_t *tcp);
63 void xml_out_frame_ppm(FILE* xmlout, opj_cp_t *cp);
64 void xml_out_frame_ppt(FILE* xmlout, opj_tcp_t *tcp);
65 void xml_out_frame_tlm(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP.  TLM NOT SAVED IN DATA STRUCTURE */
66 void xml_out_frame_plm(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP.  PLM NOT SAVED IN DATA STRUCTURE.  opt in main; can be used in conjunction with PLT */
67 void xml_out_frame_plt(FILE* xmlout, opj_tcp_t *tcp); /* NO-OP.  PLM NOT SAVED IN DATA STRUCTURE.  opt in main; can be used in conjunction with PLT */
68 void xml_out_frame_crg(FILE* xmlout); /* j2k_default_tcp is passed globally */ /* opt in main; */
69 void xml_out_frame_com(FILE* xmlout, opj_tcp_t *tcp); /* NO-OP.  COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
70 void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s);
71 void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len, char* s);
72 void xml_out_frame_jp2h(FILE* xmlout, opj_jp2_t *jp2_struct);
73 #ifdef NOTYET
74 /* Shown with cp, extended, as data structure... but it could be a new different one */
75 void xml_out_frame_jp2i(FILE* xmlout, opj_cp_t *cp);/* IntellectualProperty 'jp2i' (no restrictions on location) */
76 void xml_out_frame_xml(FILE* xmlout, opj_cp_t *cp); /* XML 'xml\040' (0x786d6c20).  Can appear multiply */
77 void xml_out_frame_uuid(FILE* xmlout, opj_cp_t *cp); /* UUID 'uuid' (top level only) */
78 void xml_out_frame_uinf(FILE* xmlout, opj_cp_t *cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
79 void xml_out_frame_unknown_type(FILE* xmlout, opj_cp_t *cp);
80 #endif
81
82
83 void xml_write_init(BOOL n, BOOL t, BOOL r, BOOL d)
84 {
85   /* Init file globals */
86   notes = n;
87   sampletables = t;
88   raw = r;
89   derived = d;
90 }
91
92 int xml_write_struct(FILE* file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, char* stringDTD, opj_event_mgr_t *event_mgr) {
93
94   if(stringDTD != NULL)
95   {
96     fprintf(xmlout,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
97         /* stringDTD is known to start with "SYSTEM " or "PUBLIC " */
98         /* typical: SYSTEM mj2_to_metadata.dtd */
99         stringDTD[6] = '\0'; /* Break into two strings at space, so quotes can be inserted. */
100     fprintf(xmlout,"<!DOCTYPE MJ2_File %s \"%s\">\n", stringDTD, stringDTD+7); 
101         stringDTD[6] = ' '; /* restore for sake of debugger or memory allocator */
102   } else
103     fprintf(xmlout,"<?xml version=\"1.0\" standalone=\"yes\"?>\n");    
104
105   fprintf(xmlout, "<MJ2_File>\n");
106   xml_write_overall_header(file, xmlout, movie, sampleframe, event_mgr);
107   fprintf(xmlout, "</MJ2_File>");
108   return 0;
109 }
110
111 /* ------------- */
112
113 int xml_write_overall_header(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr)
114 {
115   int i;
116   char buf[5];
117   buf[4] = '\0';
118
119   fprintf(xmlout,   "  <JP2 BoxType=\"jP[space][space]\" Signature=\"0x0d0a870a\" />\n");
120   // Called after structure initialized by mj2_read_ftyp
121   fprintf(xmlout,   "  <FileType BoxType=\"ftyp\">\n");
122   uint_to_chars(movie->brand, buf);
123   fprintf(xmlout,   "    <Brand>%s</Brand>\n", buf);    /* 4 character; BR              */
124   fprintf(xmlout,   "    <MinorVersion>%u</MinorVersion>\n", movie->minversion);    /* 4 char; MinV            */
125   fprintf(xmlout,   "    <CompatibilityList Count=\"%d\">\n",movie->num_cl);
126   for (i = movie->num_cl - 1; i > -1; i--) /* read routine stored in reverse order, so let's undo damage */
127   {
128     uint_to_chars(movie->cl[i], buf);
129     fprintf(xmlout, "      <CompatibleBrand>%s</CompatibleBrand>\n", buf);    /*4 characters, each CLi */
130   }
131   fprintf(xmlout,   "    </CompatibilityList>\n");
132   fprintf(xmlout,   "  </FileType>\n");
133   xml_write_moov(file, xmlout, movie, sampleframe, event_mgr);
134   // To come?              <mdat>  // This is the container for media data that can also be accessed through track structures,
135                                    // so is redundant, and simply not of interest as metadata
136   //                       <moof>  // Allows incremental build up of movie.  Probably not in Simple Profile
137   xml_write_free_and_skip(xmlout, movie); /* NO OP so far */ /* May be a place where user squirrels metadata */
138   xml_write_uuid(xmlout, movie); /* NO OP so far */ /* May be a place where user squirrels metadata */
139   return 0;
140 }
141
142 /* ------------- */
143
144 int xml_write_moov(FILE *file, FILE *xmlout, opj_mj2_t * movie, unsigned int sampleframe, opj_event_mgr_t *event_mgr)
145 {
146   unsigned int tnum;
147   mj2_tk_t *track;
148
149   fprintf(xmlout,   "  <MovieBox BoxType=\"moov\">\n");
150   fprintf(xmlout,   "    <MovieHeader BoxType=\"mvhd\">\n");
151   fprintf(xmlout,   "      <CreationTime>\n");
152   if(raw)
153     fprintf(xmlout, "        <InSeconds>%u</InSeconds>\n", movie->creation_time);
154   if(notes)
155     fprintf(xmlout, "        <!-- Seconds since start of Jan. 1, 1904 UTC (Greenwich) -->\n");
156   /*  2082844800 = seconds between 1/1/04 and 1/1/70 */
157   /* There's still a time zone offset problem not solved... but spec is ambigous as to whether stored time
158      should be local or UTC */
159   if(derived) {
160     fprintf(xmlout, "        <AsLocalTime>"); 
161                              xml_time_out(xmlout, movie->creation_time - 2082844800);
162                                                      fprintf(xmlout,"</AsLocalTime>\n");
163   }
164   fprintf(xmlout,   "      </CreationTime>\n");
165   fprintf(xmlout,   "      <ModificationTime>\n");
166   if(raw)
167     fprintf(xmlout, "        <InSeconds>%u</InSeconds>\n", movie->modification_time);
168   if(derived) {
169     fprintf(xmlout, "        <AsLocalTime>"); 
170                              xml_time_out(xmlout, movie->modification_time - 2082844800);
171                                                      fprintf(xmlout,"</AsLocalTime>\n");
172   }
173   fprintf(xmlout,   "      </ModificationTime>\n");
174   fprintf(xmlout,   "      <Timescale>%d</Timescale>\n", movie->timescale);
175   if(notes)
176     fprintf(xmlout, "      <!-- Timescale defines time units in one second -->\n");
177   fprintf(xmlout,   "      <Rate>\n");        /* Rate to play presentation  (default = 0x00010000)          */
178   if(notes) {
179     fprintf(xmlout, "      <!-- Rate to play presentation is stored as fixed-point binary 16.16 value. Decimal value is approximation. -->\n");
180     fprintf(xmlout, "      <!-- Rate is expressed relative to normal (default) value of 0x00010000 (1.0) -->\n");
181   }
182   if(raw)
183     fprintf(xmlout, "        <AsHex>0x%08x</AsHex>\n", movie->rate);
184   if(derived)
185     fprintf(xmlout, "        <AsDecimal>%12.6f</AsDecimal>\n", (double)movie->rate/(double)0x00010000);
186   fprintf(xmlout,   "      </Rate>\n");
187   fprintf(xmlout,   "      <Duration>\n");
188   if(raw)
189     fprintf(xmlout, "        <InTimeUnits>%u</InTimeUnits>\n", movie->duration);
190   if(derived)
191     fprintf(xmlout, "        <InSeconds>%12.3f</InSeconds>\n", (double)movie->duration/(double)movie->timescale);    // Make this double later to get fractional seconds
192   fprintf(xmlout,   "      </Duration>\n");
193 #ifdef CURRENTSTRUCT
194   movie->volume = movie->volume << 8;
195 #endif
196   fprintf(xmlout,   "      <Volume>\n");
197   if(notes) {
198     fprintf(xmlout, "      <!-- Audio volume stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
199     fprintf(xmlout, "      <!-- Full, normal (default) value is 0x0100 (1.0) -->\n");
200   }
201   if(raw)
202     fprintf(xmlout, "        <AsHex>0x%04x</AsHex>\n", movie->volume);
203   if(derived)
204     fprintf(xmlout, "        <AsDecimal>%6.3f</AsDecimal>\n", (double)movie->volume/(double)0x0100);
205   fprintf(xmlout,   "      </Volume>\n");
206 #ifdef CURRENTSTRUCT
207   if(notes)
208     fprintf(xmlout, "      <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
209   movie->volume = movie->volume >> 8;
210 #endif
211   /* Transformation matrix for video                            */
212   fprintf(xmlout,   "      <TransformationMatrix>\n");
213   if(notes) {
214     fprintf(xmlout, "      <!-- 3 x 3 Video Transformation Matrix {a,b,u,c,d,v,x,y,w}.  Required: u=0, v=0, w=1 -->\n");
215     fprintf(xmlout, "      <!-- Maps decompressed point (p,q) to rendered point (ap + cq + x, bp + dq + y) -->\n");
216     fprintf(xmlout, "      <!-- Stored as Fixed Point Hex: all are binary 16.16, except u,v,w are 2.30 -->\n");
217     fprintf(xmlout, "      <!-- Unity = 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 -->\n");
218   }
219   fprintf(xmlout,   "        <TMa>0x%08x</TMa>\n", movie->trans_matrix[0]);    
220   fprintf(xmlout,   "        <TMb>0x%08x</TMb>\n", movie->trans_matrix[1]);    
221   fprintf(xmlout,   "        <TMu>0x%08x</TMu>\n", movie->trans_matrix[2]);    
222   fprintf(xmlout,   "        <TMc>0x%08x</TMc>\n", movie->trans_matrix[3]);    
223   fprintf(xmlout,   "        <TMd>0x%08x</TMd>\n", movie->trans_matrix[4]);    
224   fprintf(xmlout,   "        <TMv>0x%08x</TMv>\n", movie->trans_matrix[5]);    
225   fprintf(xmlout,   "        <TMx>0x%08x</TMx>\n", movie->trans_matrix[6]);    
226   fprintf(xmlout,   "        <TMy>0x%08x</TMy>\n", movie->trans_matrix[7]);    
227   fprintf(xmlout,   "        <TMw>0x%08x</TMw>\n", movie->trans_matrix[8]);
228   fprintf(xmlout,   "      </TransformationMatrix>\n");
229   fprintf(xmlout,   "    </MovieHeader>\n");
230   
231   fprintf(xmlout,   "    <Statistics>\n");
232   fprintf(xmlout,   "      <TracksFound>\n");
233   fprintf(xmlout,   "        <Video>%d</Video>\n", movie->num_vtk);
234   fprintf(xmlout,   "        <Audio>%d</Audio>\n", movie->num_stk);
235   fprintf(xmlout,   "        <Hint>%d</Hint>\n", movie->num_htk);
236   if(notes)
237     fprintf(xmlout, "        <!-- Hint tracks for streaming video are not part of MJ2, but are a defined extension. -->\n");
238   /* See Part 3 Amend 2 Section 4.2 for relation of MJ2 to Part 12 Sections 7 and 10 hints */
239   fprintf(xmlout,   "      </TracksFound>\n");
240   fprintf(xmlout,   "    </Statistics>\n");
241   /* Idea for the future:  It would be possible to add code to verify that the file values:
242     1) are legal and self-consistent
243         2) comply with particular JP2 and/or MJ2 profiles.
244         This could be reported here as additional XML elements */
245
246   // Find first video track 
247   tnum = 0;
248   while (movie->tk[tnum].track_type != 0)
249     tnum ++;
250
251   track = &(movie->tk[tnum]);
252   // For now, output info on first video track
253   xml_write_trak(file, xmlout, track, tnum, sampleframe, event_mgr);
254
255   // to come:                <MovieExtends mvek> // possibly not in Simple Profile
256   xml_write_moov_udta(xmlout, movie); /* NO OP so far */ /* <UserDataBox udta> contains <CopyrightBox cprt> */
257   fprintf(xmlout,   "  </MovieBox>\n");
258   return 0;
259 }
260
261 /* --------------- */
262
263 void uint_to_chars(unsigned int value, char* buf)
264 {
265         /* buf is at least char[5] */
266     int i;
267     for (i = 3; i >= 0; i--)
268     {
269         buf[i] = (value & 0x000000ff);
270         value = (value >> 8);
271     }
272         buf[4] = '\0'; /* Precautionary */
273 }
274
275 /* ------------- */
276
277 /* WINDOWS SPECIFIC */
278
279 void UnixTimeToFileTime(time_t t, LPFILETIME pft)
280 {
281   /* Windows specific.  From MS Q167296 */
282   /* 'time_t' represents seconds since midnight January 1, 1970 UTC (coordinated universal time). */
283   /* 64-bit FILETIME structure represents the number of 100-nanosecond intervals since January 1, 1601 UTC (coordinate universal time). */
284   LONGLONG ll; /* LONGLONG is a 64-bit value. */
285   ll = Int32x32To64(t, 10000000) + 116444736000000000;
286   pft->dwLowDateTime = (DWORD)ll;
287   /* pft->dwLowDateTime = (DWORD)(0x00000000ffffffff & ll); */
288   pft->dwHighDateTime = (DWORD)(ll >> 32);
289
290 // Once the UNIX time is converted to a FILETIME structure,
291 // other Win32 time formats can be easily obtained by using Win32 functions such
292 // as FileTimeToSystemTime() and FileTimeToDosDateTime().
293
294 /* ------------- */
295
296 void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst)
297 {
298   /* Windows specific */
299   FILETIME ft;
300   UnixTimeToFileTime(t, &ft);
301   FileTimeToLocalFileTime( &ft, &ft ); /* Adjust from UTC to local time zone */
302   FileTimeToSystemTime(&ft, pst);
303 }
304
305 /* ------------- */
306
307 void xml_time_out(FILE* xmlout, time_t t)
308 {
309   /* Windows specific */
310   SYSTEMTIME st;
311   char szLocalDate[255], szLocalTime[255];
312   UnixTimeToSystemTime( t, &st );
313   GetDateFormat( LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szLocalDate, 255 );
314   GetTimeFormat( LOCALE_USER_DEFAULT, 0, &st, NULL, szLocalTime, 255 );
315   fprintf(xmlout, "%s %s", szLocalDate, szLocalTime ); 
316 }
317
318 /* END WINDOWS SPECIFIC */
319
320 /* ------------- */
321
322 void xml_write_moov_udta(FILE* xmlout, opj_mj2_t * movie) {
323   /* Compare with xml_write_udta */
324 #ifdef NOTYET
325   /* NO-OP so far.  Optional UserData 'udta' (zero or one in moov or each trak)
326      can contain multiple Copyright 'cprt' with different language codes */
327   /* There may be nested non-standard boxes within udta */
328   IMAGINE movie->udta, movie->copyright_count, movie->copyright_language[i] (array of 16bit ints), movie->copyright_notice[i] (array of buffers)
329   PROBABLY ALSO NEED movie->udta_len or special handler for non-standard boxes
330   char buf[5];
331   int i;
332
333   if(movie->udta != 1)
334           return; /* Not present */
335
336   fprintf(xmlout,    "    <UserData BoxType=\"udta\">\n");
337   for(i = 0; i < movie->copyright_count; i++) {
338     fprintf(xmlout,  "      <Copyright BoxType=\"cprt\"> Instance=\"%d\">\n", i+1);
339     int16_to_3packedchars((short int)movie->copyright_languages[i], buf);
340     fprintf(xmlout,  "        <Language>%s</Language>\n", buf);    /* 3 chars */
341     fprintf(xmlout,  "        <Notice>%s</Notice>\n",movie->copyright_notices[i]);
342     fprintf(xmlout,  "      </Copyright>\n", i+1);
343   }
344   /* TO DO: Non-standard boxes */
345   fprintf(xmlout,    "    </UserData>\n");
346 #endif
347 }
348
349 void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie) {
350 #ifdef NOTYET
351   /* NO-OP so far.  There can be zero or more instances of free and/or skip
352      at the top level of the file.  This may be a place where the user squirrel's metadata.
353          Let's assume unstructured, and do a dump */
354   IMAGINE movie->free_and_skip, movie->free_and_skip_count, movie->free_and_skip_content[i] (array of buffers),
355           movie->free_and_skip_len[i] (array of ints), movie->is_skip[i] (array of BOOL)
356   int i;
357
358   if(movie->free_and_skip != 1)
359           return; /* Not present */
360
361   for(i = 0; i < movie->free_and_skip_count; i++) {
362     if(movie->is_skip[i])
363       fprintf(xmlout,    "  <Skip BoxType=\"skip\">\n");
364         else
365       fprintf(xmlout,    "  <Free BoxType=\"free\">\n");
366
367     xml_out_dump_hex_and_ascii(xmlout, movie->free_and_skip_contents[i], movie->free_and_skip_len[i]);
368
369     if(movie->is_skip[i])
370       fprintf(xmlout,    "  </Skip>\n");
371         else
372       fprintf(xmlout,    "  </Free>\n");
373   }
374 #endif
375 }
376
377 void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie) {
378 /* Univeral Unique IDs of 16 bytes.  */
379 #ifdef NOTYET
380   /* NO-OP so far.  There can be zero or more instances of private uuid boxes in a file.
381      This function supports the top level of the file, but uuid may be elsewhere [not yet supported].
382          This may be a place where the user squirrel's metadata.  Let's assume unstructured, and do a dump */
383   IMAGINE movie->uuid, movie->uuid_count, movie->uuid_content[i] (array of buffers),
384           movie->uuid_len[i] (array of ints), movie->uuid_type[i] (array of 17-byte (16+null termination) buffers)
385   int i;
386
387   if(movie->uuid != 1)
388           return; /* Not present */
389
390   for(i = 0; i < movie->uuid_count; i++) {
391     fprintf(xmlout,    "  <PrivateExtension BoxType=\"uuid\" UUID=\"%s\">\n", movie->uuid_type[i]);
392         // See Part III section 5.2.1, 6.1, 6.2
393     xml_out_dump_hex_and_ascii(xmlout, movie->uuid_contents[i], movie->uuid_len[i]);
394     fprintf(xmlout,    "  </PrivateExtension>\n");
395   }
396 #endif
397 }
398
399 /* ------------- */
400
401 void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum, unsigned int sampleframe, opj_event_mgr_t *event_mgr)
402 {
403   fprintf(xmlout,    "    <Track BoxType=\"trak\" Instance=\"%d\">\n", tnum);
404   xml_write_tkhd(file, xmlout, track, tnum);
405   // TO DO: TrackReferenceContainer 'tref'  just used in hint track
406   // TO DO: EditListContainer 'edts', contains EditList 'elst' with media-time, segment-duration, media-rate
407   xml_write_mdia(file, xmlout, track, tnum);
408   xml_write_udta(file, xmlout, track, tnum); // NO-OP so far.  Optional UserData 'udta', can contain multiple Copyright 'cprt'
409
410   if(track->track_type==0) { /* Only do for visual track */
411         /* sampleframe is from user option -f.  1 = first frame */
412     /* sampleframe of 0 is a user requests: no jp2 header */
413         /* Treat out-of-bounds values in the same way */
414         if(sampleframe > 0 && sampleframe <= track->num_samples) 
415     {
416       mj2_sample_t *sample;
417       unsigned int snum;
418
419       snum = sampleframe-1;
420       // Someday maybe do a smart range scan... for (snum=0; snum < track->num_samples; snum++){
421       //  fprintf(stdout,"Frame %d: ",snum+1);
422       sample = &track->sample[snum];
423           if(xml_out_frame(file, xmlout, sample, snum, event_mgr))
424             return; /* Not great error handling here */
425     }
426   }
427   fprintf(xmlout,    "    </Track>\n");
428 }
429
430 /* ------------- */
431
432 void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum)
433 {
434   fprintf(xmlout,    "      <TrackHeader BoxType=\"tkhd\">\n");
435   if(notes) {
436     fprintf(xmlout,  "      <!-- Not shown here: CreationTime, ModificationTime, Duration. -->\n");
437     fprintf(xmlout,  "      <!-- These 3 fields are reported under MediaHeader below.   When reading these 3, -->\n");
438     fprintf(xmlout,  "      <!-- m2j_to_metadata currently doesn't distinguish between TrackHeader and MediaHeader source. -->\n");
439     fprintf(xmlout,  "      <!-- If both found, value read from MediaHeader is used. -->\n");
440   }
441   fprintf(xmlout,    "        <TrackID>%u</TrackID>\n", track->track_ID);
442   if(track->track_type==0) /* For visual track */
443   {
444     fprintf(xmlout,  "        <TrackLayer>%d</TrackLayer>\n", track->layer);
445     if(notes)
446       fprintf(xmlout,"        <!-- front-to-back ordering of video tracks. 0 = normal, -1 is closer, etc. -->\n");
447   }
448   if(track->track_type!=0) /* volume irrelevant for visual track */
449   {
450 #ifdef CURRENTSTRUCT
451     track->volume = track->volume << 8;
452 #endif
453     fprintf(xmlout,  "        <Volume>\n");
454         if(notes) {
455       fprintf(xmlout,"          <!-- Track audio volume stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
456       fprintf(xmlout,"          <!-- Full, normal (default) value is 0x0100 (1.0) -->\n");
457         }
458         if(raw)
459       fprintf(xmlout,"          <AsHex>0x%04x</AsHex>\n", track->volume);
460         if(derived)
461       fprintf(xmlout,"          <AsDecimal>%6.3f</AsDecimal>\n", (double)track->volume/(double)0x0100);
462     fprintf(xmlout,  "        </Volume>\n");
463 #ifdef CURRENTSTRUCT
464   if(notes)
465     fprintf(xmlout,  "        <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
466         track->volume = track->volume >> 8;
467 #endif
468   }
469   if(track->track_type==0)
470   {
471     /* Transformation matrix for video                            */
472     fprintf(xmlout,  "        <TransformationMatrix>\n");
473         if(notes) {
474       fprintf(xmlout,"          <!-- Comments about matrix in MovieHeader apply here as well. -->\n");
475       fprintf(xmlout,"          <!-- This matrix is applied before MovieHeader one. -->\n");
476         }
477     fprintf(xmlout,  "          <TMa>0x%08x</TMa>\n", track->trans_matrix[0]);    
478     fprintf(xmlout,  "          <TMb>0x%08x</TMb>\n", track->trans_matrix[1]);    
479     fprintf(xmlout,  "          <TMu>0x%08x</TMu>\n", track->trans_matrix[2]);    
480     fprintf(xmlout,  "          <TMc>0x%08x</TMc>\n", track->trans_matrix[3]);    
481     fprintf(xmlout,  "          <TMd>0x%08x</TMd>\n", track->trans_matrix[4]);    
482     fprintf(xmlout,  "          <TMv>0x%08x</TMv>\n", track->trans_matrix[5]);    
483     fprintf(xmlout,  "          <TMx>0x%08x</TMx>\n", track->trans_matrix[6]);    
484     fprintf(xmlout,  "          <TMy>0x%08x</TMy>\n", track->trans_matrix[7]);    
485     fprintf(xmlout,  "          <TMw>0x%08x</TMw>\n", track->trans_matrix[8]);
486     fprintf(xmlout,  "        </TransformationMatrix>\n");
487   }
488 #ifdef CURRENTSTRUCT
489   track->w = track->w << 16;
490   track->h = track->h << 16;
491 #endif
492   if(notes) {
493     fprintf(xmlout,  "        <!-- Width and Height in pixels are for the presentation; frames will be scaled to this. -->\n");
494     fprintf(xmlout,  "        <!-- Both stored as fixed-point binary 16.16 values. Decimal values are approximations. -->\n");
495   }
496   fprintf(xmlout,    "        <Width>\n");
497   if(raw)
498     fprintf(xmlout,  "          <AsHex>0x%08x</AsHex>\n", track->w);
499   if(derived)
500     fprintf(xmlout,  "          <AsDecimal>%12.6f</AsDecimal>\n", (double)track->w/(double)0x00010000);        /* Rate to play presentation  (default = 0x00010000)          */
501   fprintf(xmlout,    "        </Width>\n");
502   fprintf(xmlout,    "        <Height>\n");
503   if(raw)
504     fprintf(xmlout,  "          <AsHex>0x%08x</AsHex>\n", track->h);
505   if(derived)
506     fprintf(xmlout,  "          <AsDecimal>%12.6f</AsDecimal>\n", (double)track->h/(double)0x00010000);        /* Rate to play presentation  (default = 0x00010000)          */
507   fprintf(xmlout,    "        </Height>\n");
508 #ifdef CURRENTSTRUCT
509   if(notes) {
510     fprintf(xmlout,  "        <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
511     fprintf(xmlout,  "        <!-- Also, width and height values shown here will actually be those read from track's <VisualSampleEntry> if given. -->\n");
512   }
513   track->w = track->w >> 16;
514   track->h = track->h >> 16;
515 #endif
516   fprintf(xmlout,    "      </TrackHeader>\n");
517 }
518
519 /* ------------- */
520
521 void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum) {
522   /* NO-OP so far.  Optional UserData 'udta' (zero or one in moov or each trak)
523      can contain multiple Copyright 'cprt' with different language codes */
524   /* There may be nested non-standard boxes within udta */
525 #ifdef NOTYET
526   IMAGINE track->udta, track->copyright_count, track->copyright_language[i] (array of 16bit ints), track->copyright_notice[i] (array of buffers)
527   PROBABLY ALSO NEED track->udta_len or special handler for non-standard boxes
528   char buf[5];
529   int i;
530
531   if(track->udta != 1)
532           return; /* Not present */
533
534   fprintf(xmlout,    "      <UserData BoxType=\"udta\">\n");
535   for(i = 0; i < track->copyright_count; i++) {
536     fprintf(xmlout,  "        <Copyright BoxType=\"cprt\"> Instance=\"%d\">\n", i+1);
537     int16_to_3packedchars((short int)track->copyright_languages[i], buf);
538     fprintf(xmlout,  "          <Language>%s</Language>\n", buf);    /* 3 chars */
539     fprintf(xmlout,  "          <Notice>%s</Notice>\n",track->copyright_notices[i]);
540     fprintf(xmlout,  "        </Copyright>\n", i+1);
541   }
542   /* TO DO: Non-standard boxes */
543   fprintf(xmlout,    "      </UserData>\n");
544 #endif
545 }
546
547 /* ------------- */
548
549 void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum)
550 {
551   char buf[5];
552   int i, k;
553   buf[4] = '\0';
554
555   fprintf(xmlout,    "      <Media BoxType=\"mdia\">\n");
556   fprintf(xmlout,    "        <MediaHeader BoxType=\"mdhd\">\n");
557   fprintf(xmlout,    "          <CreationTime>\n");
558   if(raw)
559     fprintf(xmlout,  "            <InSeconds>%u</InSeconds>\n", track->creation_time);
560   if(notes)
561     fprintf(xmlout,  "            <!-- Seconds since start of Jan. 1, 1904 UTC (Greenwich) -->\n");
562   /*  2082844800 = seconds between 1/1/04 and 1/1/70 */
563   /* There's still a time zone offset problem not solved... but spec is ambigous as to whether stored time
564      should be local or UTC */
565   if(derived) {
566     fprintf(xmlout,  "            <AsLocalTime>"); 
567                                 xml_time_out(xmlout, track->creation_time - 2082844800);
568                                                      fprintf(xmlout,"</AsLocalTime>\n");
569   }
570   fprintf(xmlout,    "          </CreationTime>\n");
571   fprintf(xmlout,    "          <ModificationTime>\n");
572   if(raw)
573     fprintf(xmlout,  "            <InSeconds>%u</InSeconds>\n", track->modification_time);
574   if(derived) {
575     fprintf(xmlout,  "            <AsLocalTime>"); 
576                                 xml_time_out(xmlout, track->modification_time - 2082844800);
577                                                      fprintf(xmlout,"</AsLocalTime>\n");
578   }
579   fprintf(xmlout,    "          </ModificationTime>\n");
580   fprintf(xmlout,    "          <Timescale>%d</Timescale>\n", track->timescale);
581   if(notes)
582     fprintf(xmlout,  "          <!-- Timescale defines time units in one second -->\n");
583   fprintf(xmlout,    "          <Duration>\n");
584   if(raw)
585     fprintf(xmlout,  "            <InTimeUnits>%u</InTimeUnits>\n", track->duration);
586   if(derived)
587     fprintf(xmlout,  "            <InSeconds>%12.3f</InSeconds>\n", (double)track->duration/(double)track->timescale);    // Make this double later to get fractional seconds
588   fprintf(xmlout,    "          </Duration>\n");
589   int16_to_3packedchars((short int)track->language, buf);
590   fprintf(xmlout,    "          <Language>%s</Language>\n", buf);    /* 3 chars */
591   fprintf(xmlout,    "        </MediaHeader>\n");
592   fprintf(xmlout,    "        <HandlerReference BoxType=\"hdlr\">\n");
593   switch(track->track_type)
594   {
595   case 0:
596     fprintf(xmlout,  "          <HandlerType Code=\"vide\">video media track</HandlerType>\n"); break;
597   case 1:
598     fprintf(xmlout,  "          <HandlerType Code=\"soun\">Sound</HandlerType>\n"); break;
599   case 2:
600     fprintf(xmlout,  "          <HandlerType Code=\"hint\">Hint</HandlerType>\n"); break;
601   }
602   if(notes) {
603     fprintf(xmlout,  "          <!-- String value shown is not actually read from file. -->\n");
604     fprintf(xmlout,  "          <!-- Shown value is one used for our encode. -->\n");
605   }
606   fprintf(xmlout,    "        </HandlerReference>\n");
607   fprintf(xmlout,    "        <MediaInfoContainer BoxType=\"minf\">\n");
608   switch(track->track_type)
609   {
610   case 0:
611     fprintf(xmlout,  "          <VideoMediaHeader BoxType=\"vmhd\">\n");
612     fprintf(xmlout,  "            <GraphicsMode>0x%02x</GraphicsMode>\n", track->graphicsmode);
613         if(notes) {
614       fprintf(xmlout,"            <!-- Enumerated values of graphics mode: -->\n");
615       fprintf(xmlout,"            <!--  0x00 = copy (over existing image); -->\n");
616       fprintf(xmlout,"            <!--  0x24 = transparent; 'blue-screen' this image using opcolor; -->\n");
617       fprintf(xmlout,"            <!--  0x100 = alpha; alpha-blend this image -->\n");
618 /*    fprintf(xmlout,"            <!--  0x101 = whitealpha; alpha-blend this image, which has been blended with white; -->\n"); This was evidently dropped upon amendment */
619       fprintf(xmlout,"            <!--  0x102 = pre-multiplied black alpha; image has been already been alpha-blended with black. -->\n");
620       fprintf(xmlout,"            <!--  0x110 = component alpha; blend alpha channel(s) and color channels individually. -->\n");
621         }
622     fprintf(xmlout,  "            <Opcolor>\n");
623     fprintf(xmlout,  "              <Red>0x%02x</Red>\n", track->opcolor[0]);
624     fprintf(xmlout,  "              <Green>0x%02x</Green>\n",track->opcolor[1]);
625     fprintf(xmlout,  "              <Blue>0x%02x</Blue>\n",track->opcolor[2]);
626     fprintf(xmlout,  "            </Opcolor>\n");
627     fprintf(xmlout,  "          </VideoMediaHeader>\n");
628     break;
629   case 1:
630     fprintf(xmlout,  "          <SoundMediaHeader BoxType=\"smhd\">\n");
631 #ifdef CURRENTSTRUCT
632         track->balance = track->balance << 8;
633 #endif
634     fprintf(xmlout,  "            <Balance>\n");
635         if(notes) {
636       fprintf(xmlout,"              <!-- Track audio balance fixes mono track in stereo space. -->\n");
637       fprintf(xmlout,"              <!-- Stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n");
638       fprintf(xmlout,"              <!-- 0.0 = center, -1.0 = full left, 1.0 = full right -->\n");
639         }
640         if(raw)
641       fprintf(xmlout,"              <AsHex>0x%04x</AsHex>\n", track->balance);
642     if(derived)
643           fprintf(xmlout,"              <AsDecimal>%6.3f</AsDecimal>\n", (double)track->balance/(double)0x0100);
644     fprintf(xmlout,  "            </Balance>\n");
645 #ifdef CURRENTSTRUCT
646     if(notes)
647           fprintf(xmlout,"            <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n");
648         track->balance = track->balance >> 8;
649 #endif
650     fprintf(xmlout,  "          </SoundMediaHeader>\n");
651     break;
652   case 2:
653     fprintf(xmlout,  "          <HintMediaHeader BoxType=\"hmhd\">\n");
654     fprintf(xmlout,  "            <MaxPDU_Size>%d</MaxPDU_Size>\n", track->maxPDUsize);
655     if(notes)
656       fprintf(xmlout,"            <!-- Size in bytes of largest PDU in this hint stream. -->\n");
657     fprintf(xmlout,  "            <AvgPDU_Size>%d</AvgPDU_Size>\n", track->avgPDUsize);
658     if(notes)
659       fprintf(xmlout,"            <!-- Average size in bytes of a PDU over the entire presentation. -->\n");
660     fprintf(xmlout,  "            <MaxBitRate>%d</MaxBitRate>\n", track->maxbitrate);
661     if(notes)
662       fprintf(xmlout,"            <!-- Maximum rate in bits per second over any window of 1 second. -->\n");
663     fprintf(xmlout,  "            <AvgBitRate>%d</AvgBitRate>\n", track->avgbitrate);
664     if(notes)
665       fprintf(xmlout,"            <!-- Averate rate in bits per second over the entire presentation. -->\n");
666     fprintf(xmlout,  "            <SlidingAvgBit>%d</SlidingAvgBitRate>\n", track->slidingavgbitrate);
667     if(notes)
668       fprintf(xmlout,"            <!-- Maximum rate in bits per second over any window of one minute. -->\n");
669     fprintf(xmlout,  "          </HintMediaHeader>\n");
670     break;
671   }
672   fprintf(xmlout,    "          <DataInfo BoxType=\"dinf\">\n");
673   fprintf(xmlout,    "            <DataReference BoxType=\"dref\"  URL_Count=\"%d\" URN_Count=\"%d\">\n", track->num_url, track->num_urn); // table w. flags, URLs, URNs
674   // Data structure does not distinguish between single URL, single URN, or DREF table or URLs & URNs.
675   // We could infer those, but for now just present everything as a DREF table.
676   if(notes)
677     fprintf(xmlout,  "              <!-- No entries here mean that file is self-contained, as required by Simple Profile. -->\n");
678   for(k = 0; k < track->num_url; k++) {
679     fprintf(xmlout,  "            <DataEntryUrlBox BoxType=\"url[space]\">\n"); // table w. flags, URLs, URNs
680     if(notes)
681       fprintf(xmlout,"              <!-- Only the first 16 bytes of URL location are recorded in mj2_to_metadata data structure. -->\n");
682     for(i = 0; i < 4; i++) {
683       uint_to_chars(track->url[track->num_url].location[i], buf);
684     fprintf(xmlout,  "              <Location>%s</Location>\n");
685     }
686     fprintf(xmlout,  "            </DataEntryUrlBox>\n"); // table w. flags, URLs, URNs
687   }
688   for(k = 0; k < track->num_urn; k++) {
689     fprintf(xmlout,"            <DataEntryUrnBox BoxType=\"urn[space]\">\n"); // table w. flags, URLs, URNs
690     // Only the first 16 bytes are recorded in the data structure currently.
691     if(notes)
692       fprintf(xmlout,"              <!-- Only the first 16 bytes each of URN name and optional location are recorded in mj2_to_metadata data structure. -->\n");
693     fprintf(xmlout,  "              <Name>");
694     for(i = 0; i < 4; i++) {
695       uint_to_chars(track->urn[track->num_urn].name[i], buf);
696       fprintf(xmlout,"%s", buf);
697     }
698     fprintf(xmlout,  "</Name>\n");
699     fprintf(xmlout,  "              <Location>");
700     for(i = 0; i < 4; i++) {
701       uint_to_chars(track->urn[track->num_urn].location[i], buf);
702       fprintf(xmlout,"%s");
703     }
704     fprintf(xmlout,  "</Location>\n");
705     fprintf(xmlout,  "            </DataEntryUrnBox>\n");
706   }
707   fprintf(xmlout,    "            </DataReference>\n");
708   fprintf(xmlout,    "          </DataInfo>\n");
709
710   xml_write_stbl(file, xmlout, track, tnum); /* SampleTable */
711
712   fprintf(xmlout,    "        </MediaInfoContainer>\n");  
713   fprintf(xmlout,    "      </Media>\n");
714 }
715
716 /* ------------- */
717
718 void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, unsigned int tnum)
719 {
720   char buf[5], buf33[33];
721   int i, len;
722   buf[4] = '\0';
723
724   fprintf(xmlout,      "          <SampleTable BoxType=\"stbl\">\n");
725   if(notes)
726     fprintf(xmlout,    "            <!-- What follows are specific instances of generic SampleDescription BoxType=\"stsd\" -->\n");
727   switch(track->track_type)
728   {
729   case 0:
730     // There could be multiple instances of this, but "entry_count" is just a local at read-time.
731     // And it's used wrong, too, as count of just visual type, when it's really all 3 types.
732     // This is referred to as "smj2" within mj2.c
733     fprintf(xmlout,    "            <VisualSampleEntry BoxType=\"mjp2\">\n");
734         if(notes) {
735       fprintf(xmlout,  "            <!-- If multiple instances of this box, only first is shown here. -->\n");
736           fprintf(xmlout,  "            <!-- Width and Height are in pixels.  Unlike the Track Header, there is no fractional part. -->\n");
737           fprintf(xmlout,  "            <!-- In mj2_to_metadata implementation, the values are not represented separately from Track Header's values. -->\n");
738         }
739         /* No shifting required.  If CURRENTSTRUCT gets changed, then may need to revisit treatment of these */
740     fprintf(xmlout,    "              <WidthAsInteger>%d</WidthAsInteger>\n", track->w);
741     fprintf(xmlout,    "              <HeightAsInteger>%d</HeightAsInteger>\n", track->h);
742 // Horizresolution and vertresolution don't require shifting, already stored right in CURRENTSTRUCT
743     if(notes) {
744       fprintf(xmlout,  "              <!-- Resolutions are in pixels per inch, for the highest-resolution component (typically luminance). -->\n");
745       fprintf(xmlout,  "              <!-- Both stored as fixed-point binary 16.16 values. Decimal values are approximations. -->\n");
746       fprintf(xmlout,  "              <!-- Typical value for both resolutions is 0x00480000  (72.0) -->\n");
747         }
748     fprintf(xmlout,    "              <HorizontalRes>\n");
749         if(raw)
750       fprintf(xmlout,  "                <AsHex>0x%08x</AsHex>\n", track->horizresolution);
751         if(derived)
752       fprintf(xmlout,  "                <AsDecimal>%12.6f</AsDecimal>\n", (double)track->horizresolution/(double)0x00010000);        /* Rate to play presentation  (default = 0x00010000)          */
753     fprintf(xmlout,    "              </HorizontalRes>\n");
754     fprintf(xmlout,    "              <VerticalRes>\n");
755         if(raw)
756       fprintf(xmlout,  "                <AsHex>0x%08x</AsHex>\n", track->vertresolution);
757         if(derived)
758       fprintf(xmlout,  "                <AsDecimal>%12.6f</AsDecimal>\n", (double)track->vertresolution/(double)0x00010000);        /* Rate to play presentation  (default = 0x00010000)          */
759     fprintf(xmlout,    "              </VerticalRes>\n");
760
761     buf33[0] = '\0';
762     for(i = 0; i < 8; i++) {
763       uint_to_chars((unsigned int)track->compressorname[i], buf);
764       strcat(buf33, buf); /* This loads up (4 * 8) + 1 chars, but trailing ones are usually junk */
765     }
766     len = (int)buf33[0]; /* First byte has string length in bytes.  There may be garbage beyond it. */
767     buf33[len+1] = '\0'; /* Suppress it */
768     fprintf(xmlout,    "              <CompressorName>%s</CompressorName>\n", buf33+1); /* Start beyond first byte */
769         if(notes) {
770       fprintf(xmlout,  "              <!-- Compressor name for debugging.  Standard restricts max length to 31 bytes. -->\n");
771       fprintf(xmlout,  "              <!-- Usually blank or \"Motion JPEG2000\" -->\n");
772         }
773     fprintf(xmlout,    "              <Depth>0x%02x</Depth>\n",track->depth);
774         if(notes) {
775       fprintf(xmlout,  "              <!-- Depth is: -->\n");
776       fprintf(xmlout,  "              <!--   0x20: alpha channels present (color or grayscale) -->\n");
777       fprintf(xmlout,  "              <!--   0x28: grayscale without alpha -->\n");
778       fprintf(xmlout,  "              <!--   0x18: color without alpha -->\n");
779         }
780
781     xml_out_frame_jp2h(xmlout, &(track->jp2_struct));  /* JP2 Header */
782     
783   /* Following subboxes are optional */
784     fprintf(xmlout,    "              <FieldCoding BoxType=\"fiel\">\n");
785     fprintf(xmlout,    "                <FieldCount>%d</FieldCount>\n", (unsigned int)track->fieldcount); /* uchar as 1 byte uint */
786     if(notes)
787       fprintf(xmlout,  "                <!-- Must be either 1 or 2 -->\n");
788     fprintf(xmlout,    "                <FieldOrder>%d</FieldOrder>\n", (unsigned int)track->fieldorder); /* uchar as 1 byte uint */
789         if(notes) {
790       fprintf(xmlout,  "                <!-- When FieldCount=2, FieldOrder means: -->\n");
791       fprintf(xmlout,  "                <!--   0: Field coding unknown -->\n");
792       fprintf(xmlout,  "                <!--   1: Field with topmost line is stored first in sample; fields are in temporal order -->\n");
793       fprintf(xmlout,  "                <!--   6: Field with topmost line is stored second in sample; fields are in temporal order -->\n");
794       fprintf(xmlout,  "                <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present -->\n");
795       fprintf(xmlout,  "                <!-- Current implementation doesn't retain whether box was actually present. -->\n");
796         }
797     fprintf(xmlout,    "              </FieldCoding>\n");
798
799     fprintf(xmlout,    "              <MJP2_Profile BoxType=\"jp2p\" Count=\"%d\">\n",track->num_br);
800     for (i = 0; i < track->num_br; i++) /* read routine stored in reverse order, so let's undo damage */
801     {
802       uint_to_chars(track->br[i], buf);
803       fprintf(xmlout,  "                <CompatibleBrand>%s</CompatibleBrand>\n", buf);    /*4 characters, each CLi */
804     }
805     fprintf(xmlout,    "              </MJP2_Profile>\n");
806
807     fprintf(xmlout,    "              <MJP2_Prefix BoxType=\"jp2x\" Count=\"%d\">\n",track->num_jp2x);
808     for (i = 0; i < track->num_jp2x; i++)
809     { // We'll probably need better formatting than this
810       fprintf(xmlout,  "                <Data>0x%02x</Data>\n", track->jp2xdata[i]);    /* Each entry is single byte */
811     }
812     fprintf(xmlout,    "              </MJP2_Prefix>\n");
813
814     fprintf(xmlout,    "              <MJP2_SubSampling BoxType=\"jsub\">\n"); /* These values are all 1 byte */
815     if(notes)
816           fprintf(xmlout,  "              <!-- Typical subsample value is 2 for 4:2:0 -->\n");
817     fprintf(xmlout,    "                <HorizontalSub>%d</HorizontalSub>\n", track->hsub);
818     fprintf(xmlout,    "                <VerticalSub>%d</VerticalSub>\n", track->vsub);
819     fprintf(xmlout,    "                <HorizontalOffset>%d</HorizontalOffset>\n", track->hoff);
820     fprintf(xmlout,    "                <VerticalOffset>%d</VerticalOffset>\n", track->voff);
821         if(notes) {
822           fprintf(xmlout,  "                <!-- Typical {horizontal, vertical} chroma offset values: -->\n");
823           fprintf(xmlout,  "                <!-- 4:2:2 format (CCIR601, H.262, MPEG2, MPEG4, recom. Exif): {0, 0} -->\n");
824           fprintf(xmlout,  "                <!-- 4:2:2 format (JFIF):                                      {1, 0} -->\n");
825           fprintf(xmlout,  "                <!-- 4:2:0 format (H.262, MPEG2, MPEG4):                       {0, 1} -->\n");
826           fprintf(xmlout,  "                <!-- 4:2:0 format (MPEG1, H.261, JFIF, recom. Exif):           {1, 1} -->\n");
827         }
828     fprintf(xmlout,    "              </MJP2_SubSampling>\n"); /* These values are all 1 byte */
829
830     fprintf(xmlout,    "              <MJP2_OriginalFormat BoxType=\"orfo\">\n"); /* Part III Appx. 2 */
831     fprintf(xmlout,    "                <OriginalFieldCount>%u</OriginalFieldCount>\n", (unsigned int)track->or_fieldcount); /* uchar as 1-byte uint */
832     if(notes)
833       fprintf(xmlout,  "                <!-- In original material before encoding.  Must be either 1 or 2 -->\n");
834     fprintf(xmlout,    "                <OriginalFieldOrder>%u</OriginalFieldOrder>\n", (unsigned int)track->or_fieldorder); /* uchar as 1-byte uint */
835         if(notes) {
836       fprintf(xmlout,  "                <!-- When FieldCount=2, FieldOrder means: -->\n");
837       fprintf(xmlout,  "                <!--   0: Field coding unknown -->\n");
838       fprintf(xmlout,  "                <!--   11: Topmost line came from the earlier field; -->\n");
839       fprintf(xmlout,  "                <!--   16:  Topmost line came form the later field. -->\n");
840       fprintf(xmlout,  "                <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present -->\n");
841       fprintf(xmlout,  "                <!-- Current implementation doesn't retain whether box was actually present. -->\n");
842         }
843     fprintf(xmlout,    "              </MJP2_OriginalFormat>\n");
844     fprintf(xmlout,    "            </VisualSampleEntry>\n");
845     break;
846   case 1: case 2:
847     if(notes)
848       fprintf(xmlout,  "            <!-- mj2_to_metadata's data structure doesn't record this currently. -->\n"); break;
849   }
850   fprintf(xmlout,      "            <TimeToSample BoxType=\"stts\">\n");  
851   fprintf(xmlout,      "              <SampleStatistics>\n");  
852   fprintf(xmlout,      "                <TotalSamples>%d</TotalSamples>\n", track->num_samples);
853   if(notes)
854     fprintf(xmlout,    "                <!-- For video, gives the total frames in the track, by summing all entries in the Sample Table -->\n");
855   fprintf(xmlout,      "              </SampleStatistics>\n"); 
856   fprintf(xmlout,      "              <SampleEntries EntryCount=\"%d\">\n", track->num_tts);
857   for (i = 0; i < track->num_tts; i++) {
858     fprintf(xmlout,    "                <Table Entry=\"%u\" SampleCount=\"%d\" SampleDelta=\"%u\" />\n",
859                                       i+1, track->tts[i].sample_count, track->tts[i].sample_delta);
860   }
861   fprintf(xmlout,      "              </SampleEntries>\n");
862   fprintf(xmlout,      "            </TimeToSample>\n");
863
864   fprintf(xmlout,      "            <SampleToChunk BoxType=\"stsc\" Count=\"%d\">\n", track->num_samplestochunk);
865   for (i = 0; i < track->num_samplestochunk; i++) {
866     fprintf(xmlout,    "              <FirstChunk>%u</FirstChunk>\n",track->sampletochunk[i].first_chunk); /* 4 bytes */
867     fprintf(xmlout,    "              <SamplesPerChunk>%u</SamplesPerChunk>\n",track->sampletochunk[i].samples_per_chunk); /* 4 bytes */
868     fprintf(xmlout,    "              <SampleDescrIndex>%u</SampleDescrIndex>\n",track->sampletochunk[i].sample_descr_idx); /* 4 bytes */
869   }
870   fprintf(xmlout,      "            </SampleToChunk>\n");
871   // After reading this info in, track->num_chunks is calculated and a decompressed table established internally.
872
873   fprintf(xmlout,      "            <SampleSize BoxType=\"stsz\">\n");
874   if(track->same_sample_size) {
875     // all values in track->sample[i].sample_size are equal.  Grab the first one.
876     fprintf(xmlout,    "              <Sample_Size>%u</Sample_Size>\n", track->sample[0].sample_size);
877         if(notes) {
878       fprintf(xmlout,  "              <!-- Non-zero value means all samples have that size. -->\n");
879           fprintf(xmlout,  "              <!-- So <Sample_Count> (aka Entry_Count in std.) has no meaning, is suppressed from this output, and no table follows. -->\n");
880         }
881   } else {
882     fprintf(xmlout,    "              <Sample_Size>0</Sample_Size>\n");
883     if(notes)
884           if(sampletables)
885         fprintf(xmlout,"              <!-- Zero value means samples have different sizes, given in table next of length Sample_Count (aka Entry_Count in std). -->\n");
886           else
887         fprintf(xmlout,"              <!-- Zero value means samples have different sizes, given in table (not shown) of length Sample_Count (aka Entry_Count in std). -->\n");
888         fprintf(xmlout,    "              <Sample_Count>%u</Sample_Count>\n", track->num_samples);
889         if(sampletables)
890      for (i = 0; i < (int)track->num_samples; i++) {
891       fprintf(xmlout,  "              <EntrySize Num=\"%u\">%u</EntrySize>\n", i+1, track->sample[i].sample_size);
892      }
893   }  
894   fprintf(xmlout,      "            </SampleSize>\n");
895
896   fprintf(xmlout,      "            <ChunkOffset BoxType=\"stco\">\n");
897   // Structure not yet - Variant ChunkLargeOffset 'co64'
898   fprintf(xmlout,      "              <EntryCount>%u</EntryCount>\n", track->num_chunks);
899   if(notes) {
900     fprintf(xmlout,    "              <!-- For this implementation, EntryCount shown is one calculated during file read of <SampleToChunk> data. -->\n");
901     fprintf(xmlout,    "              <!-- Implementation will report failure during file read of <ChunkOffset> data if read entry-count disagrees. -->\n");
902   }
903   if(sampletables)
904     for (i = 0; i < (int)track->num_chunks; i++)
905       fprintf(xmlout,  "              <Chunk_Offset Num=\"%d\">%u</Chunk_Offset>\n", i+1, track->chunk[i].offset);
906   fprintf(xmlout,      "            </ChunkOffset>\n");
907
908   fprintf(xmlout,      "          </SampleTable>\n");
909 }
910
911 /* ------------- */
912
913 int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, unsigned int snum, opj_event_mgr_t *event_mgr)
914 {
915         opj_dparameters_t parameters;   /* decompression parameters */
916   opj_image_t *img;
917   opj_cp_t *cp;
918   int i;
919   int numcomps;
920   unsigned char* frame_codestream;
921         opj_dinfo_t* dinfo = NULL;      /* handle to a decompressor */
922         opj_cio_t *cio = NULL;  
923         opj_j2k_t *j2k;
924
925         /* JPEG 2000 compressed image data */
926
927         /* get a decoder handle */
928         dinfo = opj_create_decompress(CODEC_J2K);
929
930         /* catch events using our callbacks and give a local context */
931         opj_set_event_mgr((opj_common_ptr)dinfo, event_mgr, stderr);
932
933         /* setup the decoder decoding parameters using the current image and user parameters */
934         parameters.cp_limit_decoding = DECODE_ALL_BUT_PACKETS;
935         opj_setup_decoder(dinfo, &parameters);  
936
937   frame_codestream = (unsigned char*) malloc (sample->sample_size-8); /* Skipping JP2C marker */
938   if(frame_codestream == NULL)
939           return 1;
940
941   fseek(file,sample->offset+8,SEEK_SET);
942   fread(frame_codestream,sample->sample_size-8,1, file);  /* Assuming that jp and ftyp markers size do */
943
944         /* open a byte stream */
945         cio = opj_cio_open((opj_common_ptr)dinfo, frame_codestream, sample->sample_size-8);
946
947   /* Decode J2K to image: */
948         img = opj_decode(dinfo, cio);
949   if (!img) {
950                 fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n");
951                 opj_destroy_decompress(dinfo);
952                 opj_cio_close(cio);
953                 return 1;
954         }
955
956         j2k = (opj_j2k_t*)dinfo->j2k_handle;
957         j2k_default_tcp = j2k->default_tcp;
958         cp = j2k->cp;
959
960   numcomps = img->numcomps;
961   /*  Alignments:        "      <       To help maintain xml pretty-printing */  
962   fprintf(xmlout,      "      <JP2_Frame Num=\"%d\">\n", snum+1);
963   fprintf(xmlout,      "        <MainHeader>\n");
964   /* There can be multiple codestreams; a particular image is entirely within a single codestream */
965   /* TO DO:  A frame can be represented by two I-guess-contigious codestreams if its interleaved. */
966   fprintf(xmlout,      "          <StartOfCodestream Marker=\"SOC\" />\n");
967   /* "cp" stands for "coding parameter"; "tcp" is tile coding parameters, "tccp" is tile-component coding parameters */
968   xml_out_frame_siz(xmlout, img, cp); /* reqd in main */
969   xml_out_frame_cod(xmlout, j2k_default_tcp); /* reqd in main */
970   xml_out_frame_coc(xmlout, j2k_default_tcp, numcomps); /* opt in main, at most 1 per component */
971   xml_out_frame_qcd(xmlout, j2k_default_tcp); /* reqd in main */
972   xml_out_frame_qcc(xmlout, j2k_default_tcp, numcomps); /* opt in main, at most 1 per component */
973   xml_out_frame_rgn(xmlout, j2k_default_tcp, numcomps); /* opt, at most 1 per component */
974   xml_out_frame_poc(xmlout, j2k_default_tcp); /*  opt (but reqd in main or tile for any progression order changes) */
975   /* Next four get j2k_default_tcp passed globally: */
976 #ifdef SUPPRESS_FOR_NOW
977   xml_out_frame_ppm(xmlout, cp); /* opt (but either PPM or PPT [distributed in tile headers] or codestream packet header reqd) */
978 #endif
979   xml_out_frame_tlm(xmlout); /* NO-OP.  TLM NOT SAVED IN DATA STRUCTURE */ /* opt */
980   xml_out_frame_plm(xmlout); /* NO-OP.  PLM NOT SAVED IN DATA STRUCTURE */ /* opt in main; can be used in conjunction with PLT */
981   xml_out_frame_crg(xmlout); /* NO-OP.  CRG NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
982   xml_out_frame_com(xmlout, j2k_default_tcp); /* NO-OP.  COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */
983
984   fprintf(xmlout,      "        </MainHeader>\n");
985
986   /*    TO DO: all the tile headers (sigh)  */
987   fprintf(xmlout,      "        <TilePartHeaders Count=\"%d\">\n", cp->tileno_size);            /* size of the vector tileno */
988   for(i = 0; i < cp->tileno_size; i++) { /* I think cp->tileno_size will be same number as (cp->tw * cp->th) or as global j2k_curtileno */
989     // Standard seems to use zero-based # for tile-part.
990     fprintf(xmlout,    "          <TilePartHeader Num=\"%d\" ID=\"%d\">\n", i, cp->tileno[i]);                  /* ID number of the tiles present in the codestream */
991     fprintf(xmlout,    "            <StartOfTilePart Marker=\"SOT\" />\n");
992         /* All markers in tile-part headers (between SOT and SOD) are optional, unless structure requires. */
993     if(i == 0) {
994       xml_out_frame_cod(xmlout, &(cp->tcps[i])); /* No more than 1 per tile */
995       xml_out_frame_coc(xmlout, &(cp->tcps[i]), numcomps); /* No more than 1 per component */
996       xml_out_frame_qcd(xmlout, &(cp->tcps[i])); /* No more than 1 per tile */
997       xml_out_frame_qcc(xmlout, &(cp->tcps[i]), numcomps);      /* No more than 1 per component */
998       xml_out_frame_rgn(xmlout, &(cp->tcps[i]), numcomps); /* No more than 1 per component */
999     }
1000     xml_out_frame_poc(xmlout, &(cp->tcps[i])); /* Reqd only if any progression order changes different from main POC */
1001 #ifdef SUPPRESS_FOR_NOW
1002     xml_out_frame_ppt(xmlout, &(cp->tcps[i])); /* Either PPT [distributed in tile headers] or PPM or codestream packet header reqd. */
1003 #endif
1004     xml_out_frame_plt(xmlout, &(cp->tcps[i])); /* NO-OP.  PLT NOT SAVED IN DATA STRUCTURE */ /* Can be used in conjunction with main's PLM */
1005     xml_out_frame_com(xmlout, &(cp->tcps[i])); /* NO-OP.  COM NOT SAVED IN DATA STRUCTURE */
1006     /* opj_tcp_t * cp->tcps; "tile coding parameters" */
1007     /* Maybe not: fprintf(xmlout,  "        <>%d</>, cp->matrice[i];                    */ /* Fixed layer    */
1008     fprintf(xmlout,    "            <StartOfData Marker=\"SOD\" />\n");
1009     if(notes)
1010       fprintf(xmlout,  "            <!-- Tile-part bitstream, not shown, follows tile-part header and SOD marker. -->\n");
1011     fprintf(xmlout,    "          </TilePartHeader>\n");
1012   }
1013   fprintf(xmlout,      "        </TilePartHeaders>\n");         /* size of the vector tileno */
1014
1015 #ifdef NOTYET
1016   IMAGINE the cp object has data to support the following... but we could use an new different data structure instead
1017   /* I'm unclear if the span of the original fread(frame_codestream...) included the following items if they're trailing. */
1018   /* ALSO TO DO, BUT DATA STRUCTURE DOESN'T HANDLE YET: boxes (anywhere in file except before the Filetype box): */
1019   xml_out_frame_jp2i(xmlout, &cp); /* IntellectualProperty 'jp2i' (no restrictions on location) */
1020   xml_out_frame_xml(xmlout, &cp); /* XML 'xml\040' (0x786d6c20).  Can appear multiply */
1021   xml_out_frame_uuid(xmlout, &cp); /* UUID 'uuid' (top level only) */
1022   xml_out_frame_uinf(xmlout, &cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
1023 #endif
1024
1025   fprintf(xmlout,      "      </JP2_Frame>\n");
1026
1027   /* Extra commentary: */
1028   if(notes) {
1029     fprintf(xmlout,    "      <!-- Given the number and size of components, mj2_to_frame would try to convert this -->\n");
1030     if (((img->numcomps == 3) && (img->comps[0].dx == img->comps[1].dx / 2) 
1031       && (img->comps[0].dx == img->comps[2].dx / 2 ) && (img->comps[0].dx == 1)) 
1032       || (img->numcomps == 1)) {
1033       fprintf(xmlout,  "      <!-- file to a YUV movie in the normal manner. -->\n");
1034     }
1035     else if ((img->numcomps == 3) && 
1036       (img->comps[0].dx == 1) && (img->comps[1].dx == 1)&&
1037           (img->comps[2].dx == 1))  {// If YUV 4:4:4 input --> to bmp
1038           fprintf(xmlout,  "      <!-- YUV 4:4:4 file to a series of .bmp files. -->\n");
1039     }
1040     else {
1041           fprintf(xmlout,  "      <!-- file whose image component dimension are unknown, to a series of .j2k files. -->\n");
1042     }
1043   }
1044
1045         opj_destroy_decompress(dinfo);
1046         opj_cio_close(cio);
1047   free(frame_codestream);
1048
1049   return 0;
1050 }
1051
1052 /* ------------- */
1053
1054 void int16_to_3packedchars(short int value, char* buf)
1055 {
1056     /* This is to retrieve the 3-letter ASCII language code */
1057     /* Each char is packed into 5 bits, as difference from 0x60 */
1058     int i;
1059     for (i = 2; i >= 0; i--)
1060     {
1061         buf[i] = (value & 0x001f) + 0x60;
1062         value = (value >>5);
1063     }
1064     buf[3] = '\0';
1065 }
1066
1067 /* ------------- */
1068
1069 void xml_out_frame_siz(FILE* xmlout, opj_image_t *img, opj_cp_t *cp)
1070 {
1071   opj_image_comp_t *comp;
1072   int i;
1073
1074   fprintf(xmlout,    "          <ImageAndFileSize Marker=\"SIZ\">\n");
1075   // This is similar to j2k.c's j2k_dump_image.
1076   // Not of interest: Lsiz, Rsiz
1077   fprintf(xmlout,    "            <Xsiz>%d</Xsiz>\n", img->x1);
1078   fprintf(xmlout,    "            <Ysiz>%d</Ysiz>\n", img->y1);
1079   if(notes)
1080     fprintf(xmlout,  "            <!-- Xsiz, Ysiz is the size of the reference grid. -->\n");
1081   fprintf(xmlout,    "            <XOsiz>%d</XOsiz>\n", img->x0);
1082   fprintf(xmlout,    "            <YOsiz>%d</YOsiz>\n", img->y0);
1083   if(notes)
1084     fprintf(xmlout,  "            <!-- XOsiz, YOsiz are offsets from grid origin to image origin. -->\n");
1085   fprintf(xmlout,    "            <XTsiz>%d</XTsiz>\n", cp->tdx);
1086   fprintf(xmlout,    "            <YTsiz>%d</YTsiz>\n", cp->tdy);
1087   if(notes)
1088     fprintf(xmlout,  "            <!-- XTsiz, YTsiz is the size of one tile with respect to the grid. -->\n");
1089   fprintf(xmlout,    "            <XTOsiz>%d</XTOsiz>\n", cp->tx0);
1090   fprintf(xmlout,    "            <YTOsiz>%d</YTOsiz>\n", cp->ty0);
1091   if(notes)
1092     fprintf(xmlout,  "            <!-- XTOsiz, YTOsiz are offsets from grid origin to first tile origin. -->\n");
1093   fprintf(xmlout,    "            <Csiz>%d</Csiz>\n", img->numcomps);
1094   if(notes) {
1095     fprintf(xmlout,  "            <!-- Csiz is the number of components in the image. -->\n");
1096     fprintf(xmlout,  "            <!-- For image components next: -->\n");
1097     fprintf(xmlout,  "            <!--   XRsiz, YRsiz denote pixel-sample-spacing on the grid, per Part I Annex B. -->\n");
1098     //fprintf(xmlout,"            <!--   XO, YO is offset of the component compared to the whole image. -->\n");
1099     fprintf(xmlout,  "            <!--   Bits per pixel (bpp) is the pixel depth. -->\n");
1100     fprintf(xmlout,  "            <!--   WidthOfData and HeightOfData are calculated values, e.g.: w = roundup((Xsiz - XOsiz)/ XRsiz) -->\n");
1101   }
1102
1103   for (i = 0; i < img->numcomps; i++) {/* image-components */
1104     comp = &(img->comps[i]);
1105     fprintf(xmlout,  "            <Component Num=\"%d\">\n", i+1);
1106     fprintf(xmlout,  "              <Ssiz>\n");
1107         if(raw)
1108       fprintf(xmlout,"                <AsHex>0x%02x</AsHex>\n", (comp->sgnd << 7) & (comp->prec - 1));
1109         if(derived) {
1110       fprintf(xmlout,"                <Signed>%d</Signed>\n", comp->sgnd);
1111       fprintf(xmlout,"                <PrecisionInBits>%d</PrecisionInBits>\n", comp->prec);
1112         }
1113     fprintf(xmlout,  "              </Ssiz>\n");
1114     fprintf(xmlout,  "              <XRsiz>%d</XRsiz>\n", comp->dx);
1115     fprintf(xmlout,  "              <YRsiz>%d</YRsiz>\n", comp->dy);
1116     fprintf(xmlout,  "              <WidthOfData>%d</WidthOfData>\n", comp->w);
1117     fprintf(xmlout,  "              <HeightOfData>%d</HeightOfData>\n", comp->h);
1118     /* Rest of these aren't calculated when SIZ is read:
1119     fprintf(xmlout,  "              <XO>%d</XO>\n", comp->x0);
1120     fprintf(xmlout,  "              <YO>%d</YO>\n", comp->y0);
1121         if(notes)
1122           fprintf(xmlout,"              <!--  XO, YO is offset of the component compared to the whole image. -->\n");
1123     fprintf(xmlout,  "              <BitsPerPixel>%d</BitsPerPixel>\n", comp->bpp);
1124     fprintf(xmlout,  "              <NumberOfDecodedResolution>%d</NumberOfDecodedResolution>\n", comp->resno_decoded); */
1125     // SUPPRESS: n/a to mj2_to_metadata.  fprintf(xmlout,"        <Factor>%d</Factor\n", comp->factor);
1126     /* factor = number of division by 2 of the out image  compare to the original size of image */
1127     // TO DO comp->data:  int *data;                    /* image-component data      */
1128
1129     fprintf(xmlout,  "            </Component>\n");
1130   }
1131   fprintf(xmlout,    "          </ImageAndFileSize>\n");
1132 }
1133
1134 /* ------------- */
1135
1136 void xml_out_frame_cod(FILE* xmlout, opj_tcp_t *tcp)
1137 {
1138 /* Could be called with tcp = &j2k_default_tcp;
1139 /* Or, for tile-part header, with &j2k_cp->tcps[j2k_curtileno]
1140 /*  Alignment for main:"          < < < <   To help maintain xml pretty-printing */  
1141 /*  Alignment for tile:"            < < <   To help maintain xml pretty-printing */  
1142   opj_tccp_t *tccp;
1143   int i;
1144   char spaces[13] = "            "; /* 12 spaces if tilepart*/
1145   char* s = spaces;
1146   if(tcp == j2k_default_tcp) {
1147     s++;s++; /* shorten s to 10 spaces if main */
1148   }
1149   tccp = &(tcp->tccps[0]);
1150
1151   fprintf(xmlout,      "%s<CodingStyleDefault Marker=\"COD\">\n",s); /* Required in main header */
1152   /* Not retained or of interest: Lcod */
1153   fprintf(xmlout,      "%s  <Scod>0x%02x</Scod>\n", s, tcp->csty); /* 1 byte */
1154   if(notes) {
1155     fprintf(xmlout,    "%s  <!-- For Scod, specific bits mean (where bit 0 is lowest or rightmost): -->\n",s);
1156     fprintf(xmlout,    "%s  <!-- bit 0: Defines entropy coder precincts -->\n",s);
1157     fprintf(xmlout,    "%s  <!--        0 = (PPx=15, PPy=15); 1 = precincts defined below. -->\n",s);
1158     fprintf(xmlout,    "%s  <!-- bit 1: 1 = SOP marker may be used; 0 = not. -->\n",s);
1159     fprintf(xmlout,    "%s  <!-- bit 2: 1 = EPH marker may be used; 0 = not. -->\n",s);
1160   }
1161   fprintf(xmlout,      "%s  <SGcod>\n",s);
1162   fprintf(xmlout,      "%s    <ProgressionOrder>%d</ProgressionOrder>\n", s, tcp->prg); /* 1 byte, SGcod (A) */
1163   if(notes) {
1164     fprintf(xmlout,    "%s    <!-- Defined Progression Order Values are: -->\n",s);
1165     fprintf(xmlout,    "%s    <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL -->\n",s);
1166     fprintf(xmlout,    "%s    <!-- where L = \"layer\", R = \"resolution level\", C = \"component\", P = \"position\". -->\n",s);
1167   }
1168   fprintf(xmlout,      "%s    <NumberOfLayers>%d</NumberOfLayers>\n", s, tcp->numlayers); /* 2 bytes, SGcod (B) */
1169   fprintf(xmlout,      "%s    <MultipleComponentTransformation>%d</MultipleComponentTransformation>\n", s, tcp->mct); /* 1 byte, SGcod (C).  More or less boolean */
1170   if(notes)
1171     fprintf(xmlout,    "%s    <!-- For MCT, 0 = none, 1 = transform first 3 components for efficiency, per Part I Annex G -->\n",s);
1172   fprintf(xmlout,      "%s  </SGcod>\n",s);
1173   /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1174   fprintf(xmlout,      "%s  <SPcod>\n",s);
1175   /* Internal data structure tccp defines separate defaults for each component, but they all get the same values */
1176   /* So we only have to report the first component's values here. */
1177   /* Compare j2k_read_cox(...) */
1178   fprintf(xmlout,      "%s    <NumberOfDecompositionLevels>%d</NumberOfDecompositionLevels>\n", s, tccp->numresolutions - 1);   /* 1 byte, SPcox (D) */
1179   fprintf(xmlout,      "%s    <CodeblockWidth>%d</CodeblockWidth>\n", s, tccp->cblkw - 2);      /* 1 byte, SPcox (E) */
1180   fprintf(xmlout,      "%s    <CodeblockHeight>%d</CodeblockHeight>\n", s, tccp->cblkh - 2);    /* 1 byte, SPcox (F) */
1181   if(notes) {
1182     fprintf(xmlout,    "%s    <!-- CBW and CBH are non-negative, and summed cannot exceed 8 -->\n",s);
1183     fprintf(xmlout,    "%s    <!-- Codeblock dimension is 2^(value + 2) -->\n", s);
1184   }
1185   fprintf(xmlout,      "%s    <CodeblockStyle>0x%02x</CodeblockStyle>\n", s, tccp->cblksty);    /* 1 byte, SPcox (G) */
1186   if(notes) {
1187     fprintf(xmlout,    "%s    <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): -->\n",s);
1188     fprintf(xmlout,    "%s    <!-- bit 0: Selective arithmetic coding bypass. -->\n",s);
1189     fprintf(xmlout,    "%s    <!-- bit 1: Reset context probabilities on coding pass boundaries. -->\n",s);
1190     fprintf(xmlout,    "%s    <!-- bit 2: Termination on each coding pass. -->\n",s);
1191     fprintf(xmlout,    "%s    <!-- bit 3: Vertically causal context. -->\n",s);
1192     fprintf(xmlout,    "%s    <!-- bit 4: Predictable termination. -->\n",s);
1193     fprintf(xmlout,    "%s    <!-- bit 5: Segmentation symbols are used. -->\n",s);
1194   }
1195   fprintf(xmlout,      "%s    <Transformation>%d</Transformation>\n", s, tccp->qmfbid); /* 1 byte, SPcox (H) */
1196   if(notes)
1197     fprintf(xmlout,    "%s    <!-- For Transformation, 0=\"9-7 irreversible filter\", 1=\"5-3 reversible filter\" -->\n",s);
1198   if (tccp->csty & J2K_CP_CSTY_PRT) {
1199     fprintf(xmlout,    "%s    <PrecinctSize>\n",s); /* 1 byte, SPcox (I_i) */
1200     if(notes)
1201       fprintf(xmlout,  "%s    <!-- These are size exponents PPx and PPy. May be zero only for first level (aka N(L)LL subband)-->\n",s);
1202     for (i = 0; i < tccp->numresolutions; i++) {        
1203       fprintf(xmlout,  "%s      <PrecinctHeightAndWidth  ResolutionLevel=\"%d\">\n", s, i);
1204           if(raw)
1205         fprintf(xmlout,"%s        <AsHex>0x%02x</AsHex>\n", s, (tccp->prch[i] << 4) | tccp->prcw[i]);   /* packed into 1 byte, SPcox (G) */
1206           if(derived) {
1207         fprintf(xmlout,"%s        <WidthAsDecimal>%d</WidthAsDecimal>\n", s, tccp->prcw[i]);
1208         fprintf(xmlout,"%s        <HeightAsDecimal>%d</HeightAsDecimal>\n", s, tccp->prch[i]);
1209           }
1210       fprintf(xmlout,  "%s      </PrecinctHeightAndWidth>\n", s, i);
1211     }
1212     fprintf(xmlout,    "%s    </PrecinctSize>\n",s); /* 1 byte, SPcox (I_i) */
1213   }
1214   fprintf(xmlout,      "%s  </SPcod>\n",s);
1215   fprintf(xmlout,      "%s</CodingStyleDefault>\n",s);
1216 }
1217
1218 /* ------------- */
1219
1220 void xml_out_frame_coc(FILE* xmlout, opj_tcp_t *tcp, int numcomps) /* Optional in main & tile-part headers */
1221 {
1222 /* Uses global j2k_default_tcp */
1223   opj_tccp_t *tccp, *firstcomp_tccp;
1224   int i, compno;
1225   char spaces[13] = "            "; /* 12 spaces if tilepart*/
1226   char* s = spaces;
1227   if(tcp == j2k_default_tcp) {
1228     s++;s++; /* shorten s to 10 spaces if main */
1229   }
1230
1231   firstcomp_tccp = &(tcp->tccps[0]);
1232     /* Internal data structure tccp defines separate defaults for each component, set from main */
1233         /* default, then selectively overwritten. */
1234     /* Compare j2k_read_cox(...) */
1235   /* We don't really know which was the default, and which were not */
1236   /* Let's pretend that [0] is the default and all others are not */
1237   if(notes) {
1238     fprintf(xmlout,    "%s<!-- mj2_to_metadata implementation always reports component[0] as using default COD, -->\n", s);
1239     if(tcp == j2k_default_tcp)
1240       fprintf(xmlout,  "%s<!-- and any other component, with main-header style values different from [0], as COC. -->\n", s);
1241     else
1242       fprintf(xmlout,  "%s<!-- and any other component, with tile-part-header style values different from [0], as COC. -->\n", s);
1243   }
1244   for (compno = 1; compno < numcomps; compno++) /* spec says components are zero-based */
1245   {
1246     tccp = &tcp->tccps[compno];
1247     if(same_component_style(firstcomp_tccp, tccp))
1248                 continue;
1249
1250 /*  Alignments:          "      < < < < <   To help maintain xml pretty-printing */  
1251     fprintf(xmlout,      "%s<CodingStyleComponent Marker=\"COC\">\n", s); /* Optional in main header, at most 1 per component */
1252     if(notes)
1253       fprintf(xmlout,    "%s  <!-- See Ccoc below for zero-based component number. -->\n", s);
1254     /* Overrides the main COD for the specific component */
1255     /* Not retained or of interest: Lcod */
1256     fprintf(xmlout,      "%s  <Scoc>0x%02x</Scoc>\n", s, tccp->csty); /* 1 byte */
1257         if(notes) {
1258           fprintf(xmlout,    "%s  <!-- Scoc defines entropy coder precincts: -->\n", s);
1259       fprintf(xmlout,    "%s  <!--   0 = maximum, namely (PPx=15, PPy=15); 1 = precincts defined below. -->\n", s);
1260         }
1261     fprintf(xmlout,      "%s  <Ccoc>%d</Ccoc>\n", s, compno); /* 1 or 2 bytes */
1262     /* Unfortunately compo isn't retained in j2k_read_coc:  compno = cio_read(j2k_img->numcomps <= 256 ? 1 : 2);        /* Ccoc */
1263     /*if(j2k_img_numcomps <=256)
1264           component is 1 byte
1265     else
1266       compno is 2 byte */
1267
1268     /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1269     fprintf(xmlout,      "%s  <SPcoc>\n", s);
1270     fprintf(xmlout,      "%s    <NumberOfDecompositionLevels>%d</NumberOfDecompositionLevels>\n", s, tccp->numresolutions - 1); /* 1 byte, SPcox (D) */
1271     fprintf(xmlout,      "%s    <CodeblockWidth>%d</CodeblockWidth>\n", s, tccp->cblkw - 2);    /* 1 byte, SPcox (E) */
1272     fprintf(xmlout,      "%s    <CodeblockHeight>%d</CodeblockHeight>\n", s, tccp->cblkh - 2);  /* 1 byte, SPcox (F) */
1273         if(notes) {
1274       fprintf(xmlout,    "%s    <!-- CBW and CBH are non-negative, and summed cannot exceed 8 -->\n", s);
1275       fprintf(xmlout,    "%s    <!-- Codeblock dimension is 2^(value + 2) -->\n", s);
1276         }
1277     fprintf(xmlout,      "%s    <CodeblockStyle>0x%02x</CodeblockStyle>\n", s, tccp->cblksty);  /* 1 byte, SPcox (G) */
1278         if(notes) {
1279       fprintf(xmlout,    "%s    <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): -->\n", s);
1280       fprintf(xmlout,    "%s    <!-- bit 0: Selective arithmetic coding bypass. -->\n", s);
1281       fprintf(xmlout,    "%s    <!-- bit 1: Reset context probabilities on coding pass boundaries. -->\n", s);
1282       fprintf(xmlout,    "%s    <!-- bit 2: Termination on each coding pass. -->\n", s);
1283       fprintf(xmlout,    "%s    <!-- bit 3: Vertically causal context. -->\n", s);
1284       fprintf(xmlout,    "%s    <!-- bit 4: Predictable termination. -->\n", s);
1285       fprintf(xmlout,    "%s    <!-- bit 5: Segmentation symbols are used. -->\n", s);
1286         }
1287     fprintf(xmlout,      "%s    <Transformation>%d</Transformation>\n", s, tccp->qmfbid);       /* 1 byte, SPcox (H) */
1288     if(notes)
1289       fprintf(xmlout,    "%s    <!-- For Transformation, 0=\"9-7 irreversible filter\", 1=\"5-3 reversible filter\" -->\n", s);
1290     if (tccp->csty & J2K_CP_CSTY_PRT) {
1291       fprintf(xmlout,    "%s    <PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */
1292       if(notes)
1293         fprintf(xmlout,  "%s      <!-- These are size exponents PPx and PPy. May be zero only for first level (aka N(L)LL subband)-->\n", s);
1294       for (i = 0; i < tccp->numresolutions-1; i++) { /* subtract 1 to get # of decomposition levels */  
1295         fprintf(xmlout,  "%s      <PrecinctHeightAndWidth  ResolutionLevel=\"%d\">\n", s, i);
1296                 if(raw)
1297           fprintf(xmlout,"%s        <AsHex>0x%02x</AsHex>\n", s, (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */
1298                 if(derived) {
1299           fprintf(xmlout,"%s        <WidthAsDecimal>%d</WidthAsDecimal>\n", s, tccp->prcw[i]);
1300           fprintf(xmlout,"%s        <HeightAsDecimal>%d</HeightAsDecimal>\n", s, tccp->prch[i]);
1301                 }
1302         fprintf(xmlout,  "%s      </PrecinctHeightAndWidth>\n", s, i);
1303       }
1304       fprintf(xmlout,    "%s    </PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */
1305     }
1306     fprintf(xmlout,      "%s  </SPcoc>\n", s);
1307     fprintf(xmlout,      "%s</CodingStyleComponent>\n", s);
1308   }
1309 }
1310
1311 /* ------------- */
1312
1313 BOOL same_component_style(opj_tccp_t *tccp1, opj_tccp_t *tccp2)
1314 {
1315   int i;
1316
1317   if(tccp1->numresolutions != tccp2->numresolutions)
1318           return FALSE;
1319   if(tccp1->cblkw != tccp2->cblkw)
1320           return FALSE;
1321   if(tccp1->cblkh != tccp2->cblkh)
1322           return FALSE;
1323   if(tccp1->cblksty != tccp2->cblksty)
1324           return FALSE;
1325   if(tccp1->csty != tccp2->csty)
1326           return FALSE;
1327   
1328   if (tccp1->csty & J2K_CP_CSTY_PRT) {
1329       for (i = 0; i < tccp1->numresolutions; i++) {     
1330          if(tccp1->prcw[i] != tccp2->prcw[i] || tccp1->prch[i] != tccp2->prch[i])
1331                          return FALSE;
1332       }
1333   }
1334   return TRUE;
1335 }
1336
1337 /* ------------- */
1338
1339 void xml_out_frame_qcd(FILE* xmlout, opj_tcp_t *tcp)
1340 {
1341   /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1342   opj_tccp_t *tccp;
1343   int bandno, numbands;
1344   char spaces[13] = "            "; /* 12 spaces if tilepart*/
1345   char* s = spaces;
1346   if(tcp == j2k_default_tcp) {
1347     s++;s++; /* shorten s to 10 spaces if main */
1348   }
1349
1350   /* Compare j2k_read_qcx */
1351   fprintf(xmlout,      "%s<QuantizationDefault Marker=\"QCD\">\n", s); /* Required in main header, single occurrence */
1352   tccp = &(tcp->tccps[0]);
1353   /* Not retained or of interest: Lqcd */
1354   fprintf(xmlout,      "%s  <Sqcd>\n", s);              /* 1 byte */
1355   if(notes)
1356     fprintf(xmlout,    "%s  <!-- Default quantization style for all components. -->\n", s);
1357   if(raw)
1358     fprintf(xmlout,    "%s    <AsHex>0x%02x</AsHex>\n", s, (tccp->numgbits) << 5 | tccp->qntsty);
1359   if(derived)
1360     fprintf(xmlout,    "%s    <QuantizationStyle>%d</QuantizationStyle>\n", s, tccp->qntsty);
1361   if(notes) {
1362     fprintf(xmlout,    "%s    <!-- Quantization style (in Sqcd's low 5 bits) may be: -->\n", s);
1363     fprintf(xmlout,    "%s    <!--   0 = No quantization. SPqcd size = 8 bits-->\n", s);
1364     fprintf(xmlout,    "%s    <!--   1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcd size = 16. -->\n", s);
1365     fprintf(xmlout,    "%s    <!--   2 = Scalar expounded (values signaled for each subband). SPqcd size = 16. -->\n", s);
1366   }
1367   if(derived)
1368     fprintf(xmlout,    "%s    <NumberOfGuardBits>%d</NumberOfGuardBits>\n", s,  tccp->numgbits);
1369   if(notes)
1370     fprintf(xmlout,    "%s    <!-- 0-7 guard bits allowed (stored in Sqcd's high 3 bits) -->\n", s);
1371   fprintf(xmlout,      "%s  </Sqcd>\n", s);
1372           
1373   /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */
1374   /* So we'll just dump all internal values */
1375   /* We could calculate it, but I'm having trouble believing the length equations in the standard */
1376   
1377   fprintf(xmlout,      "%s  <SPqcd>\n", s);
1378   switch(tccp->qntsty) {
1379   case J2K_CCP_QNTSTY_NOQNT: /* no quantization */
1380     /* This is what standard says, but I don't believe it: len = 4 + (3*decomp); */
1381     numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1382         /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1383     /* Instead look for first zero exponent, quit there.  Adequate? */
1384     fprintf(xmlout,    "%s    <ReversibleStepSizeValue>\n", s);
1385         if(notes) {
1386       fprintf(xmlout,  "%s    <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1387           fprintf(xmlout,  "%s    <!-- until an exponent with zero value is reached. -->\n", s);
1388           fprintf(xmlout,  "%s    <!-- Exponent epsilon(b) of reversible dynamic range. -->\n", s);
1389           fprintf(xmlout,  "%s    <!-- Hex value is as stored, in high-order 5 bits. -->\n", s);
1390         }
1391     for (bandno = 0; bandno < numbands; bandno++) {
1392       if(tccp->stepsizes[bandno].expn == 0)
1393         break; /* Remove when we have real numbands */
1394       fprintf(xmlout,  "%s      <DynamicRangeExponent Subband=\"%d\">\n", s, bandno);
1395           if(raw)
1396         fprintf(xmlout,"%s        <AsHex>0x%02x</AsHex>\n", s, tccp->stepsizes[bandno].expn << 3);
1397           if(derived)
1398         fprintf(xmlout,"%s        <AsDecimal>%d</AsDecimal>\n", s, tccp->stepsizes[bandno].expn);
1399       fprintf(xmlout,  "%s      </DynamicRangeExponent>\n", s);
1400     }
1401     fprintf(xmlout,    "%s    </ReversibleStepSizeValue>\n", s);
1402     break;
1403   case J2K_CCP_QNTSTY_SIQNT:  /* scalar quantization derived */
1404     /* This is what standard says.  Should I believe it:: len = 5;
1405     /* numbands = 1; */
1406     fprintf(xmlout,    "%s    <QuantizationStepSizeValues>\n", s);
1407     if(notes)
1408       fprintf(xmlout,  "%s    <!-- For irreversible transformation only.  See Part I Annex E Equation E.3 -->\n", s);
1409     fprintf(xmlout,    "%s      <QuantizationValues Subband=\"0\">\n", s);
1410     if(notes)
1411       fprintf(xmlout,  "%s      <!-- For N(L)LL subband: >\n", s);
1412         if(raw)
1413       fprintf(xmlout,  "%s        <AsHex>0x%02x</AsHex>\n", s, (tccp->stepsizes[0].expn << 11) | tccp->stepsizes[0].mant);
1414         if(derived) {
1415       fprintf(xmlout,  "%s        <Exponent>%d</Exponent>\n", s, tccp->stepsizes[0].expn);
1416       fprintf(xmlout,  "%s        <Mantissa>%d</Mantissa>\n", s, tccp->stepsizes[0].mant);
1417         }
1418     fprintf(xmlout,    "%s      </QuantizationValues>\n", s);
1419         if(notes) {
1420       fprintf(xmlout,  "%s      <!-- Exponents for subbands beyond 0 are not from header, but calculated per Eq. E.5 -->\n", s);
1421       fprintf(xmlout,  "%s      <!-- The mantissa for all subbands is the same, given by the value above. -->\n", s);
1422       fprintf(xmlout,  "%s      <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1423           fprintf(xmlout,  "%s      <!-- until a subband with exponent of zero value is reached. -->\n", s);
1424         }
1425
1426     for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) {
1427       if(tccp->stepsizes[bandno].expn == 0)
1428         break;
1429
1430       fprintf(xmlout,  "%s      <CalculatedExponent Subband=\"%d\">%d</CalculatedExponent>\n", s, bandno, tccp->stepsizes[bandno].expn);
1431     }
1432
1433     fprintf(xmlout,    "%s    </QuantizationStepSizeValues>\n", s);
1434     break;
1435
1436   default: /* J2K_CCP_QNTSTY_SEQNT */ /* scalar quantization expounded */
1437     /* This is what standard says, but should I believe it: len = 5 + 6*decomp; */
1438     numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1439         /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1440     fprintf(xmlout,    "%s    <QuantizationStepSizeValues>\n", s);
1441         if(notes) {
1442       fprintf(xmlout,  "%s    <!-- For irreversible transformation only.  See Part I Annex E Equation E.3 -->\n", s);
1443       fprintf(xmlout,  "%s    <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1444       fprintf(xmlout,  "%s    <!-- until a subband with mantissa and exponent of zero values is reached. -->\n", s);
1445     }
1446     for (bandno = 0; bandno < numbands; bandno++) {
1447       if(tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0)
1448         break; /* Remove when we have real numbands */
1449
1450       fprintf(xmlout,  "%s      <QuantizationValues Subband=\"%d\">\n", s, bandno);
1451           if(raw)
1452         fprintf(xmlout,"%s        <AsHex>0x%02x</AsHex>\n", s, (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant);
1453           if(derived) {
1454         fprintf(xmlout,"%s        <Exponent>%d</Exponent>\n", s, tccp->stepsizes[bandno].expn);
1455         fprintf(xmlout,"%s        <Mantissa>%d</Mantissa>\n", s, tccp->stepsizes[bandno].mant);
1456           }
1457       fprintf(xmlout,  "%s      </QuantizationValues>\n", s);
1458     }
1459     fprintf(xmlout,    "%s    </QuantizationStepSizeValues>\n", s);
1460     break;
1461   } /* switch */
1462   fprintf(xmlout,      "%s  </SPqcd>\n", s);
1463   fprintf(xmlout,      "%s</QuantizationDefault>\n", s);
1464
1465 /*  Alignments:        "    < < < < <   To help maintain xml pretty-printing */  
1466 }
1467
1468 /* ------------- */
1469
1470 void xml_out_frame_qcc(FILE* xmlout, opj_tcp_t *tcp, int numcomps)
1471 {
1472 /* Uses global j2k_default_tcp */
1473   /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */
1474   opj_tccp_t *tccp, *firstcomp_tccp;
1475   int bandno, numbands;
1476   int compno;
1477   char spaces[13] = "            "; /* 12 spaces if tilepart*/
1478   char* s = spaces;
1479   if(tcp == j2k_default_tcp) {
1480     s++;s++; /* shorten s to 10 spaces if main */
1481   }
1482
1483   firstcomp_tccp = &(tcp->tccps[0]);
1484     /* Internal data structure tccp defines separate defaults for each component, set from main */
1485         /* default, then selectively overwritten. */
1486     /* Compare j2k_read_qcx(...) */
1487   /* We don't really know which was the default, and which were not */
1488   /* Let's pretend that [0] is the default and all others are not */
1489   if(notes) {
1490     fprintf(xmlout,      "%s<!-- mj2_to_metadata implementation always reports component[0] as using default QCD, -->\n", s);
1491     if(tcp == j2k_default_tcp)
1492       fprintf(xmlout,    "%s<!-- and any other component, with main-header quantization values different from [0], as QCC. -->\n", s);
1493     else
1494       fprintf(xmlout,    "%s<!-- and any other component, with tile-part-header quantization values different from [0], as QCC. -->\n", s);
1495   }
1496   for (compno = 1; compno < numcomps; compno++) /* spec says components are zero-based */
1497   {
1498     tccp = &(tcp->tccps[compno]);
1499     if(same_component_quantization(firstcomp_tccp, tccp))
1500                 continue;
1501
1502     /* Compare j2k_read_qcx */
1503     fprintf(xmlout,      "%s<QuantizationComponent Marker=\"QCC\" Component=\"%d\">\n", s, compno); /* Required in main header, single occurrence */
1504     tccp = &j2k_default_tcp->tccps[0];
1505     /* Not retained or perhaps of interest: Lqcd   It maybe can be calculated.  */
1506     fprintf(xmlout,      "%s  <Sqcc>\n", s);            /* 1 byte */
1507     if(notes)
1508       fprintf(xmlout,    "%s  <!-- Quantization style for this component. -->\n", s);
1509         if(raw)
1510       fprintf(xmlout,    "%s    <AsHex>0x%02x</AsHex>\n", s, (tccp->numgbits) << 5 | tccp->qntsty);
1511         if(derived)
1512       fprintf(xmlout,    "%s    <QuantizationStyle>%d</QuantizationStyle>\n", s, tccp->qntsty);
1513         if(notes) {
1514       fprintf(xmlout,    "%s    <!-- Quantization style (in Sqcc's low 5 bits) may be: -->\n", s);
1515       fprintf(xmlout,    "%s    <!--   0 = No quantization. SPqcc size = 8 bits-->\n", s);
1516       fprintf(xmlout,    "%s    <!--   1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcc size = 16. -->\n", s);
1517       fprintf(xmlout,    "%s    <!--   2 = Scalar expounded (values signaled for each subband). SPqcc size = 16. -->\n", s);
1518         }
1519         if(derived)
1520       fprintf(xmlout,    "%s    <NumberOfGuardBits>%d</NumberOfGuardBits>\n", s,        tccp->numgbits);
1521     if(notes)
1522       fprintf(xmlout,    "%s    <!-- 0-7 guard bits allowed (stored in Sqcc's high 3 bits) -->\n", s);
1523     fprintf(xmlout,      "%s  </Sqcc>\n", s);
1524           
1525     /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */
1526     /* So we'll just dump all internal values */
1527     fprintf(xmlout,      "%s  <SPqcc>\n", s);
1528     switch(tccp->qntsty) {
1529     case J2K_CCP_QNTSTY_NOQNT:
1530       numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1531           /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1532
1533       /* Instead look for first zero exponent, quit there.  Adequate? */
1534       fprintf(xmlout,    "%s    <ReversibleStepSizeValue>\n", s);
1535           if(notes) {
1536         fprintf(xmlout,  "%s    <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1537             fprintf(xmlout,  "%s    <!-- until an exponent with zero value is reached. -->\n", s);
1538             fprintf(xmlout,  "%s    <!-- Exponent epsilon(b) of reversible dynamic range. -->\n", s);
1539             fprintf(xmlout,  "%s    <!-- Hex value is as stored, in high-order 5 bits. -->\n", s);
1540           }
1541       for (bandno = 0; bandno < numbands; bandno++) {
1542         if(tccp->stepsizes[bandno].expn == 0)
1543           break; /* Remove this once we have real numbands */
1544         fprintf(xmlout,  "%s      <Exponent Subband=\"%d\">\n", s, bandno);
1545                 if(raw)
1546           fprintf(xmlout,"%s        <AsHex>0x%02x</AsHex>\n", s, tccp->stepsizes[bandno].expn << 3);
1547                 if(derived)
1548           fprintf(xmlout,"%s        <AsDecimal>%d</AsDecimal>\n", s, tccp->stepsizes[bandno].expn);
1549         fprintf(xmlout,  "%s      </Exponent>\n", s);
1550       }
1551       fprintf(xmlout,    "%s    </ReversibleStepSizeValue>\n", s);
1552       break;
1553     case J2K_CCP_QNTSTY_SIQNT:
1554       /* numbands = 1; */
1555       fprintf(xmlout,    "%s    <QuantizationStepSizeValues>\n", s);
1556       if(notes)
1557         fprintf(xmlout,  "%s    <!-- For irreversible transformation only.  See Part I Annex E Equation E.3 -->\n", s);
1558       fprintf(xmlout,    "%s      <QuantizationValuesForSubband0>\n", s);
1559       if(notes)
1560         fprintf(xmlout,  "%s      <!-- For N(L)LL subband: >\n", s);
1561           if(raw)
1562         fprintf(xmlout,  "%s        <AsHex>0x%02x</AsHex>\n", s, (tccp->stepsizes[0].expn << 11) | tccp->stepsizes[0].mant);
1563           if(derived) {
1564         fprintf(xmlout,  "%s        <Exponent>%d</Exponent>\n", s, tccp->stepsizes[0].expn);
1565         fprintf(xmlout,  "%s        <Mantissa>%d</Mantissa>\n", s, tccp->stepsizes[0].mant);
1566           }
1567       fprintf(xmlout,    "%s      </QuantizationValuesForSubband0>\n", s);
1568           if(notes) {
1569         fprintf(xmlout,  "%s      <!-- Exponents for subbands beyond 0 are not from header, but calculated per Eq. E.5 -->\n", s);
1570         fprintf(xmlout,  "%s      <!-- The mantissa for all subbands is the same, given by the value above. -->\n", s);
1571         fprintf(xmlout,  "%s      <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1572             fprintf(xmlout,  "%s      <!-- until a subband with exponent of zero value is reached. -->\n", s);
1573         }
1574
1575       for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) {
1576         if(tccp->stepsizes[bandno].expn == 0)
1577           break;
1578
1579         fprintf(xmlout,  "%s      <CalculatedExponent Subband=\"%d\">%d</CalculatedExponent>\n", s, bandno, tccp->stepsizes[bandno].expn);
1580       }
1581       fprintf(xmlout,    "%s    </QuantizationStepSizeValues>\n", s);
1582       break;
1583
1584     default: /* J2K_CCP_QNTSTY_SEQNT */
1585       numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1586           /* Better: IMAGINE numbands = tccp->stepsize_numbands; */
1587       fprintf(xmlout,    "%s    <QuantizationStepSizeValues>\n", s);
1588       if(notes) {
1589         fprintf(xmlout,  "%s    <!-- For irreversible transformation only.  See Part I Annex E Equation E.3 -->\n", s);
1590         fprintf(xmlout,  "%s    <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", s);
1591             fprintf(xmlout,  "%s    <!-- until a subband with mantissa and exponent of zero values is reached. -->\n", s);
1592           }
1593       for (bandno = 0; bandno < numbands; bandno++) {
1594         if(tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0)
1595                         break; /* Remove this once we have real numbands count */
1596         fprintf(xmlout,  "%s      <QuantizationValues Subband=\"%d\">\n", s, bandno);
1597                 if(raw)
1598           fprintf(xmlout,"%s        <AsHex>0x%02x</AsHex>\n", s, (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant);
1599                 if(derived) {
1600           fprintf(xmlout,"%s        <Exponent>%d</Exponent>\n", s, tccp->stepsizes[bandno].expn);
1601           fprintf(xmlout,"%s        <Mantissa>%d</Mantissa>\n", s, tccp->stepsizes[bandno].mant);
1602                 }
1603         fprintf(xmlout,  "%s      </QuantizationValues>\n", s);
1604       }
1605       fprintf(xmlout,    "%s    </QuantizationStepSizeValues>\n", s);
1606       break;
1607     } /* switch */
1608     fprintf(xmlout,      "%s  </SPqcc>\n", s);
1609     fprintf(xmlout,      "%s</QuantizationComponent>\n", s);
1610   }
1611 /*  Alignments:          "    < < < < <   To help maintain xml pretty-printing */  
1612 }
1613
1614 /* ------------- */
1615
1616 BOOL same_component_quantization(opj_tccp_t *tccp1, opj_tccp_t *tccp2)
1617 {
1618   int bandno, numbands;
1619
1620   if(tccp1->qntsty != tccp2->qntsty)
1621           return FALSE;
1622   if(tccp1->numgbits != tccp2->numgbits)
1623           return FALSE;
1624
1625   switch(tccp1->qntsty) {
1626     case J2K_CCP_QNTSTY_NOQNT:
1627       numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */
1628       /* Instead look for first zero exponent, quit there.  Adequate? */
1629       for (bandno = 0; bandno < numbands; bandno++) {
1630         if(tccp1->stepsizes[bandno].expn == 0)
1631           break;
1632         if(tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn)
1633          return FALSE;
1634       }
1635       break;
1636     case J2K_CCP_QNTSTY_SIQNT:
1637       /* numbands = 1; */
1638       if(tccp1->stepsizes[0].expn != tccp2->stepsizes[0].expn || tccp1->stepsizes[0].mant != tccp2->stepsizes[0].mant)
1639         return FALSE;
1640           /* Don't need to check remainder, since they are calculated from [0] */
1641       break;
1642
1643     default: /* J2K_CCP_QNTSTY_SEQNT */
1644       numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/
1645           /* This comparison may cause us problems with trailing junk values. */
1646       for (bandno = 0; bandno < numbands; bandno++) {
1647         if(tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn || tccp1->stepsizes[bandno].mant != tccp2->stepsizes[bandno].mant);
1648           return FALSE;
1649       }
1650       break;
1651     } /* switch */
1652   return TRUE;
1653 }
1654
1655 /* ------------- */
1656
1657 void xml_out_frame_rgn(FILE* xmlout, opj_tcp_t *tcp, int numcomps)
1658 {
1659   int compno, SPrgn;
1660   /* MJ2 files can have regions of interest if hybridized with JPX Part II */
1661   char spaces[13] = "            "; /* 12 spaces if tilepart*/
1662   char* s = spaces;
1663   if(tcp == j2k_default_tcp) {
1664     s++;s++; /* shorten s to 10 spaces if main */
1665   }
1666
1667   for(compno = 0; compno < numcomps; compno++) {
1668     SPrgn = tcp->tccps[compno].roishift;        /* 1 byte; SPrgn */
1669     if(SPrgn == 0)
1670                 continue; /* Yet another kludge */
1671
1672     fprintf(xmlout,    "%s<RegionOfInterest Marker=\"RGN\">\n", s); /* Optional in main header, at most 1 per component */
1673     if(notes)
1674       fprintf(xmlout,  "%s<!-- See Crgn below for zero-based component number. -->\n", s);
1675     /* Not retained or of interest: Lrgd */
1676     fprintf(xmlout,    "%s  <Srgn>0</Srgn>\n", s); /* 1 byte */
1677     if(notes)
1678           fprintf(xmlout,  "%s  <!-- Srgn is ROI style.  Only style=0 defined: Implicit ROI (max. shift) -->\n", s);
1679     fprintf(xmlout,    "%s  <Crgn>%d</Crgn>\n", s, compno); /* 1 or 2 bytes */
1680     fprintf(xmlout,    "%s  <SPrgn>%d</SPrgn>\n", s, SPrgn); /* 1 byte */
1681     if(notes)
1682       fprintf(xmlout,  "%s  <!-- SPrgn is implicit ROI shift, i.e., binary shifting of ROI coefficients above background. -->\n", s);
1683     fprintf(xmlout,    "</RegionOfInterest\n", s); /* Optional in main header, at most 1 per component */
1684   }
1685 }
1686
1687 /* ------------- */
1688
1689 void xml_out_frame_poc(FILE* xmlout, opj_tcp_t *tcp) { /* Progression Order Change */
1690   /* Compare j2k_read_poc() */
1691   int i;
1692   opj_poc_t *poc;
1693   char spaces[13] = "            "; /* 12 spaces if tilepart*/
1694   char* s = spaces;
1695   if(tcp == j2k_default_tcp) {
1696     s++;s++; /* shorten s to 10 spaces if main */
1697   }
1698   
1699   if(tcp->POC != 1)
1700           return; /* Not present */
1701
1702   fprintf(xmlout,    "%s<ProgressionOrderChange Marker=\"POC\">\n", s); /* Optional in main header, at most 1 per component */
1703   /* j2k_read_poc seems to allow accumulation of default pocs from multiple POC segments, but does
1704   the spec really allow that? */
1705   /* 2 bytes, not retained; Lpoc */
1706   /* I probably didn't get this dump precisely right. */
1707   for (i = 0; i < tcp->numpocs; i++) {
1708     poc = &tcp->pocs[i];
1709     fprintf(xmlout,  "%s  <Progression Num=\"%d\">\n", s, i+1);
1710     fprintf(xmlout,  "%S    <RSpoc>%d</RSpoc>\n", s, poc->resno0);      /* 1 byte, RSpoc_i */
1711     if(notes)
1712           fprintf(xmlout,"%s    <!-- Resolution level index (inclusive) for progression start. Range: 0 to 33 -->\n", s);
1713     fprintf(xmlout,  "%s    <CSpoc>%d</CSpoc>\n", s, poc->compno0);/* j2k_img->numcomps <= 256 ? 1 byte : 2 bytes; CSpoc_i */
1714     if(notes)
1715       fprintf(xmlout,"%s    <!-- Component index (inclusive) for progression start. -->\n", s);
1716     fprintf(xmlout,  "%s    <LYEpoc>%d</LYEpoc>\n", s, poc->layno1); /* int_min(cio_read(2), tcp->numlayers);   /* 2 bytes; LYEpoc_i */
1717     if(notes)
1718       fprintf(xmlout,"%s    <!-- Layer index (exclusive) for progression end. -->\n", s);
1719     fprintf(xmlout,  "%s    <REpoc>%d</REpoc>\n", s, poc->resno1); /*int_min(cio_read(1), tccp->numresolutions);        /* REpoc_i */
1720     if(notes)
1721       fprintf(xmlout,"%s    <!-- Resolution level index (exclusive) for progression end. Range: RSpoc to 33 -->\n", s);
1722     fprintf(xmlout,  "%s    <CEpoc>%d</CEpoc>\n", s, poc->compno1); /* int_min(cio_read(j2k_img->numcomps <= 256 ? 1 : 2), j2k_img->numcomps);  /* CEpoc_i */
1723     if(notes)
1724           fprintf(xmlout,"%s    <!-- Component index (exclusive) for progression end.  Minimum: CSpoc -->\n", s);
1725     fprintf(xmlout,  "%s    <Ppoc>%d</Ppoc>\n", s, poc->prg); /* 1 byte Ppoc_i */
1726         if(notes) {
1727       fprintf(xmlout,"%s    <!-- Defined Progression Order Values are: -->\n", s);
1728       fprintf(xmlout,"%s    <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL -->\n", s);
1729       fprintf(xmlout,"%s    <!-- where L = \"layer\", R = \"resolution level\", C = \"component\", P = \"position\". -->\n", s);
1730         }
1731     fprintf(xmlout,  "%s  </Progression>\n", s);
1732   }
1733   fprintf(xmlout,    "%s</ProgressionOrderChange\n", s);
1734 }
1735
1736 /* ------------- */
1737
1738 #ifdef SUPPRESS_FOR_NOW
1739 /* Suppress PPM and PPT since we're not showing data from the third option, namely within the codestream, and
1740 that's evidently what frames_to_mj2 uses.  And a hex dump isn't so useful anyway */
1741
1742 void xml_out_frame_ppm(FILE *xmlout, opj_cp_t *cp) { /* For main header, not tile-part (which uses PPT instead). */
1743 /* Either the PPM or PPT is required if the packet headers are not distributed in the bit stream */
1744 /* Use of PPM and PPT are mutually exclusive. */
1745 /* Compare j2k_read_ppm() */
1746   int j;
1747   
1748   if(cp->ppm != 1)
1749           return; /* Not present */
1750 /* Main header uses indent of 10 spaces */
1751   fprintf(xmlout,    "          <PackedPacketHeadersMainHeader Marker=\"PPM\">\n"); /* Optional in main header, but if not, must be in PPT or codestream */
1752   /* 2 bytes Lppm not saved */
1753   if(notes) {
1754     fprintf(xmlout,  "          <!-- If there are multiple PPM marker segments in the main header, -->\n");
1755     fprintf(xmlout,  "          <!-- this mj2_to_metadata implementation will report them as a single consolidated PPM header. -->\n");
1756     fprintf(xmlout,  "          <!-- The implementation can't currently segregate by tile-part. -->\n");
1757     fprintf(xmlout,  "          <!-- TO DO? further map the packet headers to xml. -->\n");
1758   }
1759  
1760   /* 1 byte, not retained ; Zppm is sequence # of this PPM header */
1761   /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppm_previous: Nppm */
1762   /* Use j symbol for index instead of i, to make comparable with j2k_read_ppm */
1763   /* Not real clear whether to use ppm->store or ppm_len as upper bound */
1764   fprintf(xmlout,    "            <PackedData>\n");
1765   xml_out_dump_hex(xmlout, cp->ppm_data, cp->ppm_len);
1766   /* Dump packet headers 1 byte at a time: lppm[i][j] */
1767   fprintf(xmlout,    "            </PackedData>\n");
1768   fprintf(xmlout,    "          </PackedPacketHeadersMainHeader>\n"); /* Optional in main header, but if not, must be in PPT or codestream */
1769 }
1770
1771 /* ------------- */
1772
1773 void xml_out_frame_ppt(FILE *xmlout, opj_tcp_t *tcp) { /* For tile-part header, not main (which uses PPM instead). */
1774 /* Either the PPM or PPT is required if the packet headers are not distributed in the bit stream */
1775 /* Use of PPM and PPT are mutually exclusive. */
1776 /* Compare j2k_read_ppt() */
1777   int j;
1778   
1779   if(tcp->ppt != 1)
1780           return; /* Not present */
1781
1782   /* Tile-part indents are 12 spaces */
1783   fprintf(xmlout,    "            <PackedPacketHeadersTilePartHeader Marker=\"PPT\">\n"); /* Optional in main header, but if not, must be in PPT or codestream */
1784   /* 2 bytes Lppm not saved */
1785   if(notes) {
1786     fprintf(xmlout,  "            <!-- If there are multiple PPT marker segments in the tile-part header, -->\n");
1787     fprintf(xmlout,  "            <!-- this mj2_to_metadata implementation will report them as a single consolidated PPT header. -->\n");
1788     fprintf(xmlout,  "            <!-- The implementation can't currently segregate by tile-part. -->\n");
1789     fprintf(xmlout,  "            <!-- TO DO? further map the packet headers to xml. -->\n");
1790   }
1791  
1792   /* 1 byte, not retained ; Zppt is sequence # of this PPT header */
1793   /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppt_previous: Nppt */
1794   /* Use j symbol for index instead of i, to make comparable with j2k_read_ppt */
1795   /* Not real clear whether to use ppt->store or ppt_len as upper bound */
1796   fprintf(xmlout,    "              <PackedData>\n");
1797   xml_out_dump_hex(xmlout, tcp->ppt_data, tcp->ppt_len);
1798   /* Dump packet headers 1 byte at a time: lppt[i][j] */
1799   fprintf(xmlout,    "              </PackedData>\n");
1800   fprintf(xmlout,    "            </PackedPacketHeadersTileHeader>\n"); /* Optional in tile-part header, but if not, must be in PPM or codestream */
1801 }
1802 #endif SUPPRESS_FOR_NOW
1803
1804 /* ------------- */
1805
1806 void xml_out_frame_tlm(FILE* xmlout) { /* opt, main header only.  May be multiple. */
1807 /* Compare j2k_read_tlm()... which doesn't retain anything! */
1808 /* Plan:  Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
1809 /* Main header indents are 10 spaces */
1810 }
1811
1812 /* ------------- */
1813
1814 void xml_out_frame_plm(FILE* xmlout) { /* opt, main header only; can be used in conjunction with tile-part's PLT */
1815 /* NO-OP.  PLM NOT SAVED IN DATA STRUCTURE */
1816         /* Compare j2k_read_plm()... which doesn't retain anything! */
1817 /* Plan:  Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
1818 /* Main header indents are 10 spaces */
1819 }
1820
1821 /* ------------- */
1822
1823 void xml_out_frame_plt(FILE* xmlout, opj_tcp_t *tcp) { /* opt, tile-part headers only; can be used in conjunction with main header's PLM */
1824 /* NO-OP.  PLT NOT SAVED IN DATA STRUCTURE */
1825         /* Compare j2k_read_plt()... which doesn't retain anything! */
1826 /* Tile-part header indents are 12 spaces */
1827 }
1828
1829 /* ------------- */
1830
1831 void xml_out_frame_crg(FILE* xmlout) { /* NO-OP.  CRG NOT SAVED IN DATA STRUCTURE */ /* opt, main header only; */
1832 /* Compare j2k_read_crg()... which doesn't retain anything! */
1833 /* Plan:  Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */
1834 #ifdef NOTYET
1835   THIS PSEUDOCODE IMAGINES THESE EXIST: j2k_default_tcp->crg, j2k_default_tcp->crg_i, j2k_default_tcp->crg_xcrg*, j2k_default_tcp->crg_ycrg* 
1836   (POSSIBLY DON'T NEED crg_i, CAN GET NUMBER OR COMPONENTS FROM ELSEWHERE)
1837   if(j2k_default_tcp->crg != 1 || j2k_default_tcp->crg_i == 0)
1838           return; /* Not present */
1839
1840 /* Main header indents are 10 spaces */
1841   fprintf(xmlout,    "          <ComponentRegistration Marker=\"RG\" Count=\"%d\">\n", j2k_default_tcp->crg_i);
1842   if(notes) {
1843     fprintf(xmlout,  "          <!-- Fine tuning of registration of components with respect to each other, -->\n");
1844     fprintf(xmlout,  "          <!-- not required but potentially helpful for decoder. -->\n");
1845     fprintf(xmlout,  "          <!-- These supplementary fractional offsets are in units of 1/65536 of the horizontal -->\n");
1846     fprintf(xmlout,  "          <!-- or vertical separation (e.g., XRsiz[i] or YRsiz[i] for component i). -->\n");
1847   }
1848   /* This isn't the most compact form of table, but is OK when number of components is small, as is likely. */
1849   for (i = 0; i < j2k_default_tcp->crg_i; i++) {
1850     fprintf(xmlout,  "            <Component Num=\"%d\">\n", i+1);
1851     fprintf(xmlout,  "              <Xcrg>\n");
1852         if(raw)
1853       fprintf(xmlout,"                <AsNumerator>%d</AsNumerator>\n", j2k_default_tcp->crg_xcrg[i]);
1854         if(derived) {
1855           /* Calculate n * 100%/65536; 4 digits after decimal point is sufficiently accurate */
1856       fprintf(xmlout,"                <AsPercentage>%.4f</AsPercentage>\n", ((double)j2k_default_tcp->crg_xcrg[i])/655.36);
1857           /* We could do another calculation that include XRsiz[i]; maybe later. */
1858         }
1859     fprintf(xmlout,  "              </Xcrg>\n");
1860     fprintf(xmlout,  "              <Ycrg>\n");
1861         if(raw)
1862       fprintf(xmlout,"                <AsNumerator>%d</AsNumerator>\n", j2k_default_tcp->crg_ycrg[i]);
1863         if(derived) {
1864       fprintf(xmlout,"                <AsPercentage>%f</AsPercentage>\n", ((double)j2k_default_tcp->crg_ycrg[i])/655.36);
1865         }
1866     fprintf(xmlout,  "              </Ycrg>\n");
1867     fprintf(xmlout,  "            </Component>\n");
1868   }
1869
1870   fprintf(xmlout,    "          </ComponentRegistration>\n");
1871
1872 #endif
1873 }
1874
1875 /* ------------- */
1876
1877 /* Regrettably from a metadata point of view, j2k_read_com() skips over any comments in main header or tile-part-header */
1878 void xml_out_frame_com(FILE* xmlout, opj_tcp_t *tcp) { /* NO-OP.  COM NOT SAVED IN DATA STRUCTURE */ /* opt in main or tile-part headers; */
1879 /* Compare j2k_read_com()... which doesn't retain anything! */
1880 #ifdef NOTYET
1881   char spaces[13] = "            "; /* 12 spaces if tilepart*/
1882   char* s = spaces;
1883   if(tcp == &j2k_default_tcp) {
1884     s++;s++; /* shorten s to 10 spaces if main */
1885   }
1886   THIS PSEUDOCODE IMAGINES THESE EXIST: tcp->com, tcp->com_len, tcp->com_data array 
1887   if(tcp->com != 1)
1888           return; /* Not present */
1889
1890   fprintf(xmlout,    "%s<Comment Marker=\"COM\">\n", s); /* Optional in main or tile-part header */
1891   xml_out_dump_hex_and_ascii(tcp->com_data, tcp->com_len, s);
1892   fprintf(xmlout,    "%s</Comment>\n", s);
1893 #endif
1894 }
1895
1896 void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s) {
1897   /* s is a string of spaces for indent */
1898   int i;
1899   
1900   /* This is called when raw is true, or there is no appropriate derived form */
1901   fprintf(xmlout,    "%s<AsHex>\n", s);
1902   fprintf(xmlout,    "%s  ", s); /* Inadequate for pretty printing */
1903   for (i = 0; i < data_len; i++) {      /* Dump packet headers */
1904     fprintf(xmlout,  "%02x", data[i]);
1905   }
1906   fprintf(xmlout,    "%s</AsHex>\n", s);
1907 }
1908
1909 /* Define this as an even number: */
1910 #define BYTES_PER_DUMP_LINE 40
1911 /* Current total width for Hex and ASCII is : 11 spaces lead + (3 * BPDL) + 2 spaces + BPDL */
1912 void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len, char* s) {
1913   /* s is a string of spaces for indent */
1914   int i,j;
1915   
1916   if(raw)
1917     xml_out_dump_hex(xmlout, data, data_len, s);
1918
1919   if(derived) {
1920     fprintf(xmlout,  "%s<AsHexAndASCII>\n", s);
1921         for (i = 0; i < data_len; ) {
1922       fprintf(xmlout,"%s ", s); /* Additional leading space added in loop */
1923           /* First column: hex */
1924       for (j = 0; j < BYTES_PER_DUMP_LINE; j++) /* Dump bytes */
1925         fprintf(xmlout," %02x", data[i+j]);
1926       /* Space between columns... */ fprintf(xmlout,  "  ");
1927           /* Second column: ASCII */
1928           for (j = 0; j < BYTES_PER_DUMP_LINE; j++, i++) {
1929             if(isprint((int)data[i]) && i < data_len)
1930           fprintf(xmlout,"%c", data[i]);
1931             else
1932               fprintf(xmlout," ");
1933       }
1934       /* If we also wanted to output UCS-2 Unicode as a third column, then entire document
1935       must use fwprintf.  Forget about it for now.  As it stands, if data is UCS-2 format but still
1936       the ASCII set, then we'll be able to read every other byte as ASCII in column 2.  If
1937       data is UTF-8 format but still ASCII, then we'll be able to read every byte as ASCII
1938       in column 2. */
1939     }
1940     fprintf(xmlout,  "%s</AsHexAndASCII>\n", s);
1941   }
1942 }
1943
1944
1945 /* ------------- */
1946
1947 void xml_out_frame_jp2h(FILE* xmlout, opj_jp2_t *jp2_struct) {  /* JP2 Header */
1948 /* Compare jp2_read_jp2h(opj_jp2_t * jp2_struct) */
1949   int i;
1950
1951   fprintf(xmlout,      "              <JP2Header BoxType=\"jp2h\">\n");
1952
1953 /* Compare jp2_read_ihdr(jp2_struct)) */
1954   fprintf(xmlout,      "                <ImageHeader BoxType=\"ihdr\">\n");
1955   fprintf(xmlout,      "                  <HEIGHT>%d</HEIGHT>\n", jp2_struct->h); /* 4 bytes */
1956   fprintf(xmlout,      "                  <WIDTH>%d</WIDTH>\n", jp2_struct->w); /* 4 bytes */
1957   if(notes)
1958     fprintf(xmlout,    "                  <!-- HEIGHT here, if 2 fields per image, is of total deinterlaced height. -->\n");
1959   fprintf(xmlout,      "                  <NC>%d</NC>\n", jp2_struct->numcomps); /* 2 bytes */
1960   if(notes)
1961     fprintf(xmlout,    "                  <!-- NC is number of components -->\n"); /* 2 bytes */
1962   fprintf(xmlout,      "                  <BPC>\n"); /* 1 byte */
1963   if(jp2_struct->bpc == 255) {
1964     fprintf(xmlout,    "                    <AsHex>0x%02x</AsHex>\n", jp2_struct->bpc); /* 1 byte */
1965     if(notes)
1966       fprintf(xmlout,  "                    <!-- BPC = 0xff means bits per pixel varies with component; see table below. -->\n");
1967   } else { /* Not 0xff */
1968     if(raw) {
1969       fprintf(xmlout,  "                    <AsHex>0x%02x</AsHex>\n", jp2_struct->bpc); /* 1 byte */
1970       if(notes)
1971         fprintf(xmlout,"                    <!-- BPC = 0xff means bits per pixel varies with component; see table below. -->\n");
1972         }
1973     if(derived) {
1974       fprintf(xmlout,  "                    <BitsPerPixel>%d</BitsPerPixel>\n", jp2_struct->bpc & 0x7f);
1975       fprintf(xmlout,  "                    <Signed>%d</Signed>\n", jp2_struct->bpc >> 7);
1976         }
1977   }
1978   fprintf(xmlout,      "                  </BPC>\n");
1979   fprintf(xmlout,      "                  <C>%d</C>\n", jp2_struct->C); /* 1 byte */
1980   if(notes)
1981     fprintf(xmlout,    "                  <!-- C is compression type.  Only \"7\" is allowed to date. -->\n"); /* 2 bytes */
1982   fprintf(xmlout,      "                  <UnkC>%d</UnkC>\n", jp2_struct->UnkC); /* 1 byte */
1983   if(notes)
1984     fprintf(xmlout,    "                  <!-- Colourspace Unknown. 1 = unknown, 0 = known (e.g., colourspace spec is accurate) -->\n"); /* 1 byte */
1985   fprintf(xmlout,      "                  <IPR>%d</IPR>\n", jp2_struct->IPR); /* 1 byte */
1986   if(notes)
1987     fprintf(xmlout,    "                  <!-- IPR is 1 if frame contains an Intellectual Property box; 0 otherwise. -->\n"); /* 2 bytes */
1988   fprintf(xmlout,      "                </ImageHeader>\n");
1989
1990   if (jp2_struct->bpc == 255)
1991   {
1992     fprintf(xmlout,    "                <BitsPerComponent BoxType=\"bpcc\">\n");
1993     if(notes)
1994       fprintf(xmlout,  "                <!-- Pixel depth (range 1 to 38) is low 7 bits of hex value + 1 -->\n");
1995         /* Bits per pixel varies with components */
1996     /* Compare jp2_read_bpcc(jp2_struct) */
1997         for (i = 0; i < (int)jp2_struct->numcomps; i++) {
1998           if(raw)
1999         fprintf(xmlout,"                  <AsHex>0x%02x</AsHex>\n", jp2_struct->comps[i].bpcc); /* 1 byte */
2000           if(derived) {
2001         fprintf(xmlout,"                  <BitsPerPixel>%d</BitsPerPixel>\n", (jp2_struct->comps[i].bpcc & 0x7f)+1);
2002         fprintf(xmlout,"                  <Signed>%d</Signed>\n", jp2_struct->comps[i].bpcc >> 7);
2003           }
2004         }
2005     fprintf(xmlout,    "                </BitsPerComponent>\n");
2006   }
2007
2008   /* Compare jp2_read_colr(jp2_struct) */
2009   fprintf(xmlout,      "                <ColourSpecification BoxType=\"colr\">\n");
2010   fprintf(xmlout,      "                  <METH>%d</METH>\n", jp2_struct->meth); /* 1 byte */
2011   if(notes) {
2012     fprintf(xmlout,    "                  <!-- Valid values of specification method so far: -->\n");
2013     fprintf(xmlout,    "                  <!--   1 = Enumerated colourspace, in EnumCS field -->\n");
2014     fprintf(xmlout,    "                  <!--   2 = Restricted ICC Profile, in PROFILE field -->\n");
2015   }
2016   fprintf(xmlout,      "                  <PREC>%d</PREC>\n", jp2_struct->precedence); /* 1 byte */
2017   if(notes)
2018     fprintf(xmlout,    "                  <!-- 0 is only valid value of precedence so far. -->\n");
2019   fprintf(xmlout,      "                  <APPROX>%d</APPROX>\n", jp2_struct->approx); /* 1 byte */
2020   if(notes)
2021     fprintf(xmlout,    "                  <!-- 0 is only valid value of colourspace approximation so far. -->\n");
2022
2023   if (jp2_struct->meth == 1) {
2024     fprintf(xmlout,    "                  <EnumCS>%d</EnumCS>\n", jp2_struct->enumcs); /* 4 bytes */
2025         if(notes) {
2026           fprintf(xmlout,  "                  <!-- Valid values of enumerated MJ2 colourspace so far: -->\n");
2027           fprintf(xmlout,  "                  <!--   16: sRGB as defined by IEC 61966-2-1. -->\n");
2028           fprintf(xmlout,  "                  <!--   17: greyscale (related to sRGB). -->\n");
2029           fprintf(xmlout,  "                  <!--   18: sRGB YCC (from JPEG 2000 Part II). -->\n");
2030           fprintf(xmlout,  "                  <!-- (Additional JPX values are defined in Part II). -->\n");
2031         }
2032   }
2033   else
2034     if(notes)
2035       fprintf(xmlout,  "                  <!-- PROFILE is not handled by current OpenJPEG implementation. -->\n");
2036     /* only 1 byte is read and nothing stored */
2037   fprintf(xmlout,      "                </ColourSpecification>\n");
2038
2039   /* TO DO?  No OpenJPEG support.
2040   Palette 'pclr'
2041   ComponentMapping 'cmap'
2042   ChannelDefinition 'cdef'
2043   Resolution 'res'
2044   */
2045   fprintf(xmlout,      "              </JP2Header>\n");
2046 }
2047 /* ------------- */
2048
2049 #ifdef NOTYET
2050 IMAGE these use cp structure, extended... but we could use a new data structure instead
2051 void xml_out_frame_jp2i(FILE* xmlout, opj_cp_t *cp) {
2052   /* IntellectualProperty 'jp2i' (no restrictions on location) */
2053   int i;
2054   IMAGE cp->jp2i, cp->jp2i_count, cp->jp2i_data (array of chars), cp->cp2i_len (array of ints)
2055   if(cp->jp2i != 1)
2056           return; /* Not present */
2057
2058   for(i = 0; i < cp->jp2i_count; i++)
2059   {
2060     fprintf(xmlout,      "            <IntellectualProperty BoxType=\"jp2i\">\n");
2061   /* I think this can be anything, including binary, so do a dump */
2062     /* Is it better to indent or not indent this content?  Indent is better for reading, but
2063     worse for cut/paste. */
2064     xml_out_dump_hex_and_ascii(xmlout, cp->jp2i_data[i], cp->jp2i_len[i]);
2065     fprintf(xmlout,      "            </IntellectualProperty>\n");
2066   }
2067 }
2068
2069 void xml_out_frame_xml(FILE* xmlout, opj_cp_t *cp) {
2070   /* XML 'xml\040' (0x786d6c20).  Can appear multiply, before or after jp2c codestreams */
2071   IMAGE cp->xml, cp->xml_count, cp->xml_data (array of chars)
2072   MAYBE WE DON'T NEED cp->xml_len (array of ints) IF WE ASSUME xml_data IS NULL-TERMINATED.
2073   ASSUME ASSUME EACH LINE IS ENDED BY \n.
2074   int i;
2075   if(cp->xml != 1)
2076           return; /* Not present */
2077
2078   for(i = 0; i < cp->xml_count; i++)
2079   {
2080     fprintf(xmlout,      "            <TextFormXML BoxType=\"xml[space]" Instance=\"%d\">\n", i+1);
2081     /* Is it better to indent or not indent this content?  Indent is better for reading, but
2082     worse for cut/paste. Being lazy, didn't indent here. */
2083     fprintf(xmlout,cp->xml_data[i]); /* May be multiple lines */ /* Could check if this is well-formed */
2084     fprintf(xmlout,      "            </TextFormXML>\n");
2085   }
2086 }
2087
2088 void xml_out_frame_uuid(FILE* xmlout, opj_cp_t *cp) {
2089         /* UUID 'uuid' (top level only) */
2090         /* Part I 1.7.2 says: may appear multiply in JP2 file, anywhere except before File Type box */
2091         /* Part III 5.2.1 says: Private extensions shall be achieved through the 'uuid' type. */
2092         /* A UUID is a 16-byte value.  There is a conventional string representation for it:
2093            "0x12345678-9ABC-DEF0-1234-567890ABCDEF".  Let's assume that is what is stored in uuid_value */
2094
2095         /* Part III 6.1 Any other MJ2 box type could be alternatively written as a 'uuid' box, with value given
2096            as : 0xXXXXXXXX-0011-0010-8000-00AA00389B71, where the Xs are the boxtype in hex.  However,
2097            such a file is "not compliant; systems may choose to read [such] objects ... as equivalent to the box of
2098            the same type, or not."  Here, we choose not to. */
2099   int i;
2100   IMAGE cp->uuid, cp->uuid_count, cp->uuid_value (array of uuids... let's say fixed-length strings) cp->uuid_data (array of char buffers), cp->uuid_len (array of ints)
2101   if(cp->juuid != 1)
2102           return; /* Not present */
2103
2104   for(i = 0; i < cp->uuid_count; i++)
2105   {
2106     fprintf(xmlout,      "            <UniversalUniqueID BoxType=\"uuid\">
2107         fprintf(xmlout,      "              <UUID>%s</UUDI>\n", cp->uuid_value[i]);
2108         fprintf(xmlout,      "              <Data>\n");
2109   /* I think this can be anything, including binary, so do a dump */
2110     /* Is it better to indent or not indent this content?  Indent is better for reading, but
2111     worse for cut/paste. */
2112     xml_out_dump_hex_and_ascii(xmlout, cp->uuid_data[i], cp->uuid_len[i]);
2113         fprintf(xmlout,      "              </Data>\n");
2114     fprintf(xmlout,      "            </UniversalUniqueID>\n");
2115   }
2116 }
2117
2118 void xml_out_frame_uinf(FILE* xmlout, opj_cp_t *cp) {
2119         /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */
2120         /* Part I 1.7.3 says: may appear multiply in JP2 file, anywhere at the top level except before File Type box */
2121         /* So there may be multiple ulst's, and each can have multiple UUIDs listed (with a single URL) */
2122         /* This is not quite as vendor-specific as UUIDs, or at least is meant to be generally readable */
2123         /* Assume UUIDs stored in canonical string format */
2124   int i, j;
2125   IMAGE cp->uinf, cp->uinf_count, cp->uinf_ulst_nu (array of ints)
2126     cp->uinf_uuid (2 dimensional array of uuids... let's say fixed-length strings),
2127     cp->uinf_url (array of char buffers)
2128
2129   if(cp->uinf != 1)
2130           return; /* Not present */
2131
2132   for(i = 0; i < cp->uuid_count; i++)
2133   {
2134     fprintf(xmlout,      "            <UUIDInfo BoxType=\"uinf\">\n");
2135     fprintf(xmlout,      "              <UUIDList BoxType=\"ulst\" Count=\"%d\">\n",cp->cp->uinf_ulst_nu[i]);
2136         for(j = 0; j < cp->uinf_ulst_nu[i];  j++)
2137           fprintf(xmlout,    "              <ID Instance=\"%s\">%s</ID>\n", cp->uuif_uuid[i][j], j+1);
2138     fprintf(xmlout,      "              </UUIDList>\n");
2139         fprintf(xmlout,      "              <DataEntryURL>\n");
2140         /* Could add VERS and FLAG here */
2141         fprintf(xmlout,      "                <LOC>\n");
2142     fprintf(xmlout,      "                  %s",cp->uinf_url[i]); /* Probably single line, so indent works */ /* In theory, could check if this is well-formed, or good live link */
2143         fprintf(xmlout,      "                </LOC>\n");
2144         fprintf(xmlout,      "              </DataEntryURL>\n");
2145     fprintf(xmlout,      "            </UUIDInfo>\n");
2146   }
2147 }
2148
2149 IMAGE these use cp structure, extended... but we could use a new data structure instead
2150 void xml_out_frame_unknown_type(FILE* xmlout, opj_cp_t *cp) {
2151   /* Part III 5.2.1 says "Type fields not defined here are reserved.  Private extensions
2152      shall be acieved through the 'uuid' type." [This implies an unknown
2153      type would be an error, but then...] "Boxes not explicitly defined in this standard,
2154          or otherwise unrecognized by a reader, may be ignored."
2155          Also, it says  "the following types are not and will not be used, or used only in
2156          their existing sense, in future versions of this specification, to avoid conflict
2157          with existing content using earlier pre-standard versions of this format:
2158            clip, crgn, matt, kmat, pnot, ctab, load, imap;
2159            track reference types tmcd, chap, sync,scpt, ssrc"
2160          [But good luck figuring out the mapping.]
2161          Part III Amend. 2 4.1 is stronger: "All these specifications [of this family, e.g.,
2162          JP2 Part I, ISO Base format (Part 12) leading to MP4, Quicktime, and possibly including
2163          MJ2] require that readers ignore objects that are unrecognizable to them".
2164          */
2165   int i;
2166   IMAGE cp->unknown_type, cp->unknown_type_count, cp->unknown_type_boxtype (array of buf[5]s), cp->unknown_type_data (array of chars), cp->unknown_type_len (array of ints)
2167   if(cp->unknown_type != 1)
2168           return; /* Not present */
2169
2170   for(i = 0; i < cp->unknown_type_count; i++)
2171   {
2172     fprintf(xmlout,      "            <UnknownType BoxType=\"%s\">\n", cp->unknown_type_boxtype[i]);
2173     /* Can be anything, including binary, so do a dump */
2174     /* Is it better to indent or not indent this content?  Indent is better for reading, but
2175     worse for cut/paste. */
2176     xml_out_dump_hex_and_ascii(xmlout, cp->unknown_type_data[i], cp->unknown_type_len[i]);
2177     fprintf(xmlout,      "            </UnknownType>\n");
2178   }
2179 }
2180
2181 #endif