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