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