Patch libdvdread + TXTDT info and parsing prog

Olaf Beck <[email protected]>
Newsgroups gmane.comp.video.ogle.devel
Organization Frozenriver Digital Design
Message-ID <[email protected]>
Hello Folks

Been hacking libdvdread and cracking TXTDT (i.e. DVDTXT) all weekend but it 
has paid of :).

Firstly the patch to libdvdread is against the current CVS version of 
libdvdread see http://developer.berlios.de/cvs/?group_id=180 .

The patch implements what I hand Hakan has discussed before i.e. parental mg,  
offset tables, and some small misc changes. Anyway as always suggestions, 
test etc and mail me if you have any questions :).

I have as I said hacked DVDTXT and I have actually cracked it at least I think 
so. All the data I get from my parsing prog is consistent and it looks really 
good but as always you never know.

Attached is a doc (txtdt.txt) describing (very badly) the structure of 
TXTDT_MG and not yet finished parsing prog dvdtxt.c (doesn't dep on 
anything). 

Now about the parsing program I will continue tomorrow (dead tired) and add 
the real parsing of all types and get it to put out some nice readable info. 
As it is now it just collects the data and print the structures hence if you 
don't know what it all mean you can't interpert it. 

I will later on turn this prog into a patch for libdvdread/ifo_read.c and the 
"output" part will be added to ifo_print.c. As above  suggestions, test etc 
and mail me if you have any questions :).

Cheers Olaf

Puh: Bed time :).
dvdread.diff (text/x-diff, 15.8 KB)
diff -ur dvdread.old/ifo_print.c dvdread/ifo_print.c
--- dvdread.old/ifo_print.c	Sun Aug 18 08:19:51 2002
+++ dvdread/ifo_print.c	Sun Aug 25 23:44:04 2002
@@ -154,6 +154,17 @@
     if(attr->line21_cc_2)
       printf("2 ");
   }
+
+  switch(attr->bit_rate) {
+    case 0:
+      printf("Variable Bit Rate ");
+      break;
+    case 1:
+      printf("Constant Bit Rate ");
+      break;
+    default:
+      printf("(please send a bug report)");
+  }
   
   {
     int height = 480;
@@ -312,7 +323,7 @@
   }
     
   printf("%d ", attr->unknown1);
-  printf("%d ", attr->unknown2);
+  printf("%d ", attr->surround_karaoke);
 }
 
 static void ifoPrint_subp_attributes(int level, subp_attr_t *attr) {
@@ -320,24 +331,42 @@
   if(attr->type == 0
      && attr->lang_code == 0
      && attr->zero1 == 0
-     && attr->zero2 == 0
+     && attr->subp_code_ext == 0
      && attr->lang_extension== 0) {
     printf("-- Unspecified --");
     return;
   }
+
+  switch(attr->code_mode) {
+  case 0:
+    printf("Coding Mode RLE ");
+    break;
+  case 1:
+    printf("Coding Mode Extended ");
+    break;
+  default:
+    printf("(please send a bug report) ");
+  }    
   
-  printf("type %02x ", attr->type);
+  //printf("type %02x ", attr->type);
   
-  if(isalpha((int)(attr->lang_code >> 8))
+  /*if(isalpha((int)(attr->lang_code >> 8))
      && isalpha((int)(attr->lang_code & 0xff))) {
     printf("%c%c ", attr->lang_code >> 8, attr->lang_code & 0xff);
   } else {
     printf("%02x%02x ", 0xff & (unsigned)(attr->lang_code >> 8), 
 	   0xff & (unsigned)(attr->lang_code & 0xff));
   }
+  */
+
+  if( attr->type == 1 ) {
+      printf("%c%c ", attr->lang_code >> 8, attr->lang_code & 0xff);
+  } else {
+      printf("lang not specified ");
+  }
   
   printf("%d ", attr->zero1);
-  printf("%d ", attr->zero2);
+  printf("%d ", attr->subp_code_ext);
 
   switch(attr->lang_extension) {
   case 0:
@@ -776,6 +805,8 @@
 	 vts_ptt_srpt->nr_of_srpts, 
 	 vts_ptt_srpt->last_byte);
   for(i=0;i<vts_ptt_srpt->nr_of_srpts;i++) {
+    printf("\n\nVTS_PTT number %d has a offset %d relative to VTS_PTT_SRPT\n\n", 
+				i + 1, vts_ptt_srpt->ttu_offset[i]);
     for(j=0;j<vts_ptt_srpt->title[i].nr_of_ptts;j++) {
       printf("VTS_PTT_SRPT - Title %3i part %3i: PGC: %3i PG: %3i\n",
 	     i + 1, j + 1, 
@@ -786,38 +817,57 @@
 }
 
 
-static void hexdump(uint8_t *ptr, int len) {
+/*static void hexdump(uint8_t *ptr, int len) {
   while(len--)
     printf("%02x ", *ptr++);
-}
+}*/
 
 void ifoPrint_PTL_MAIT(ptl_mait_t *ptl_mait) {
-  int i, j;
+  int i, j, k, l;
   
   printf("Number of Countries: %i\n", ptl_mait->nr_of_countries);
   printf("Number of VTSs: %i\n", ptl_mait->nr_of_vtss);
-  //printf("Last byte: %i\n", ptl_mait->last_byte);
+  printf("Last byte: %i\n", ptl_mait->last_byte);
   
   for(i = 0; i < ptl_mait->nr_of_countries; i++) {
     printf("Country code: %c%c\n", 
 	   ptl_mait->countries[i].country_code >> 8,
 	   ptl_mait->countries[i].country_code & 0xff);
-    /*
+    
       printf("Start byte: %04x %i\n", 
       ptl_mait->countries[i].pf_ptl_mai_start_byte, 
       ptl_mait->countries[i].pf_ptl_mai_start_byte);
-    */
+  }  
+
+  for(i=0; i < ptl_mait->nr_of_countries; i++) {
+     printf("Parental Masks for the %c%c\n",
+             ptl_mait->countries[i].country_code >> 8,
+             ptl_mait->countries[i].country_code & 0xff);
+     for(k = 0, l = 8; k < 8 * (ptl_mait->nr_of_vtss + 1); k = k + ptl_mait->nr_of_vtss + 1, l--) {
+        printf("Parental Masks for level %d\n", l);
+        for(j = 0 ; j < ptl_mait->nr_of_vtss + 1 ; j++) {
+            if( j == 0) {
+              printf("Parental Mask for VMG is %02x \n", ptl_mait->countries[0].pf_ptl_mai[j+k] );
+            } else {
+              printf("Parental Mask for VTS %d is %02x \n", j, ptl_mait->countries[0].pf_ptl_mai[j+k] );
+            }
+        }
+     }
+
+  }
+
+ 
     /* This seems to be pointing at a array with 8 2byte fields per VTS
        ? and one extra for the menu? always an odd number of VTSs on
        all the dics I tested so it might be padding to even also.
        If it is for the menu it probably the first entry.  */
-    for(j=0;j<8;j++) {
+ /*   for(j=0;j<8;j++) {
       hexdump( (uint8_t *)ptl_mait->countries - PTL_MAIT_COUNTRY_SIZE 
 	       + ptl_mait->countries[i].pf_ptl_mai_start_byte
 	       + j*(ptl_mait->nr_of_vtss+1)*2, (ptl_mait->nr_of_vtss+1)*2);
       printf("\n");
-    }
-  }
+      }
+  */
 }
 
 void ifoPrint_VTS_TMAPT(vts_tmapt_t *vts_tmapt) {
@@ -825,7 +875,11 @@
   int i, j;
   
   printf("Number of VTS_TMAPS: %i\n", vts_tmapt->nr_of_tmaps);
-  //printf("Last byte: %i\n", vts_tmapt->last_byte);
+  printf("Last byte: %i\n", vts_tmapt->last_byte);
+
+  for(i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
+     printf("TMAP number %d has offset %d relative to VTS_TMAPTI\n", i + 1, vts_tmapt->vts_tmap_offset[i]);
+  }
   
   for(i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
     printf("TMAP %i\n", i);
@@ -943,7 +997,11 @@
 void ifoPrint_VTS_ATRT(vts_atrt_t *vts_atrt) {
   int i;
   
-  printf("Number of Video Title Sets: %3i\n", vts_atrt->nr_of_vtss);
+  printf("Number of Video Title Sets: %3i\n\n", vts_atrt->nr_of_vtss);
+  for(i = 0; i < vts_atrt->nr_of_vtss; i++) {
+     printf("VTS_ATRT number %d has a offset %d relative to VMG_VTS_ATRT\n", i + 1, vts_atrt->vts_atrt_offsets[i]);
+
+  }
   for(i = 0; i < vts_atrt->nr_of_vtss; i++) {
     printf("\nVideo Title Set %i\n", i + 1);
     ifoPrint_VTS_ATTRIBUTES(&vts_atrt->vts[i]);
diff -ur dvdread.old/ifo_read.c dvdread/ifo_read.c
--- dvdread.old/ifo_read.c	Sun Aug 18 08:19:51 2002
+++ dvdread/ifo_read.c	Sun Aug 25 23:42:58 2002
@@ -936,6 +936,8 @@
        of the vts_ptt_srpt structure. */
     assert(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1 + 4);
   }
+ 
+  vts_ptt_srpt->ttu_offset = data;
   
   vts_ptt_srpt->title = malloc(vts_ptt_srpt->nr_of_srpts * sizeof(ttu_t));
   if(!vts_ptt_srpt->title) {
@@ -975,7 +977,6 @@
         = *(uint16_t*)(((char *)data) + data[i] + 4*j + 2 - VTS_PTT_SRPT_SIZE);
     }
   }
-  free(data);
   
   for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) {
     for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) {
@@ -1006,6 +1007,7 @@
     int i;
     for(i = 0; i < ifofile->vts_ptt_srpt->nr_of_srpts; i++)
       free(ifofile->vts_ptt_srpt->title[i].ptt);
+    free(ifofile->vts_ptt_srpt->ttu_offset);
     free(ifofile->vts_ptt_srpt->title);
     free(ifofile->vts_ptt_srpt);
     ifofile->vts_ptt_srpt = 0;
@@ -1016,7 +1018,7 @@
 int ifoRead_PTL_MAIT(ifo_handle_t *ifofile) {
   ptl_mait_t *ptl_mait;
   int info_length;
-  unsigned int i;
+  unsigned int i,j;
 
   if(!ifofile)
     return 0;
@@ -1046,7 +1048,8 @@
   B2N_16(ptl_mait->nr_of_vtss);
   B2N_32(ptl_mait->last_byte);
   
-  info_length = ptl_mait->last_byte + 1 - PTL_MAIT_SIZE;
+  //info_length = ptl_mait->last_byte + 1 - PTL_MAIT_SIZE;
+  info_length = ptl_mait->nr_of_countries * PTL_MAIT_COUNTRY_SIZE;
   
   assert(ptl_mait->nr_of_countries != 0);
   assert(ptl_mait->nr_of_countries < 100); // ??
@@ -1064,7 +1067,9 @@
   }
   if(!(DVDReadBytes(ifofile->file, ptl_mait->countries, info_length))) {
     fprintf(stderr, "libdvdread: Unable to read PTL_MAIT.\n");
-    ifoFree_PTL_MAIT(ifofile);
+    free(ptl_mait->countries);
+    free(ptl_mait);
+    ifofile->ptl_mait = 0;
     return 0;
   }
 
@@ -1080,14 +1085,51 @@
            8 * (ptl_mait->nr_of_vtss + 1) * 2 <= ptl_mait->last_byte + 1);
   }
 
+  for(i = 0; i < ptl_mait->nr_of_countries; i++) {
+    if(!DVDFileSeek_(ifofile->file, ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN + 
+                                    ptl_mait->countries[i].pf_ptl_mai_start_byte)) {
+      fprintf(stderr, "libdvdread: Unable to seak PTL_MAIT table.\n");
+      free(ptl_mait->countries);
+      free(ptl_mait);
+      return 0;
+    }
+    info_length = (ptl_mait->nr_of_vtss + 1) * sizeof(uint16_t) * 8;
+    ptl_mait->countries[i].pf_ptl_mai = (uint16_t *)malloc(info_length);
+    if(!ptl_mait->countries[i].pf_ptl_mai) {
+      for(j = 0; j < i ; j++) {
+         free(ptl_mait->countries[j].pf_ptl_mai);
+      }
+      free(ptl_mait->countries);
+      free(ptl_mait);
+      return 0;
+    }
+    if(!(DVDReadBytes(ifofile->file,ptl_mait->countries[i].pf_ptl_mai, info_length))) {
+       fprintf(stderr, "libdvdread: Unable to read PTL_MAIT table.\n");
+       for(j = 0; j <= i ; j++) {
+	  free(ptl_mait->countries[j].pf_ptl_mai);
+       }
+       free(ptl_mait->countries);
+       free(ptl_mait);
+       return 0;
+    }
+    for (j = 0; j < ((ptl_mait->nr_of_vtss + 1) * 8); j++) {
+        B2N_16(ptl_mait->countries[i].pf_ptl_mai[j]);
+    }
+  }
   return 1;
 }
 
 void ifoFree_PTL_MAIT(ifo_handle_t *ifofile) {
+ 
+  unsigned int i;
+  
   if(!ifofile)
     return;
   
   if(ifofile->ptl_mait) {
+    for(i = 0; i < ifofile->ptl_mait->nr_of_countries; i++) {
+       free(ifofile->ptl_mait->countries[i].pf_ptl_mai);
+    }
     free(ifofile->ptl_mait->countries);
     free(ifofile->ptl_mait);
     ifofile->ptl_mait = 0;
@@ -1109,12 +1151,13 @@
 
   if(ifofile->vtsi_mat->vts_tmapt == 0) { /* optional(?) */
     ifofile->vts_tmapt = NULL;
+    fprintf(stderr,"Please send bug report - no VTS_TMAPT ?? \n");
     return 1;
   }
   
   offset = ifofile->vtsi_mat->vts_tmapt * DVD_BLOCK_LEN;
   
-  if(!DVDFileSeek_(ifofile->file, offset))
+  if(!DVDFileSeek_(ifofile->file, offset)) 
     return 0;
   
   vts_tmapt = (vts_tmapt_t *)malloc(sizeof(vts_tmapt_t));
@@ -1143,6 +1186,8 @@
     ifofile->vts_tmapt = NULL;
     return 0;
   }
+
+  vts_tmapt->vts_tmap_offset = vts_tmap_srp;
   
   if(!(DVDReadBytes(ifofile->file, vts_tmap_srp, info_length))) {
     fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n");
@@ -1151,6 +1196,11 @@
     ifofile->vts_tmapt = NULL;
     return 0;
   }
+
+  for (i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
+     B2N_32(vts_tmap_srp[i]); 
+  }
+
   
   info_length = vts_tmapt->nr_of_tmaps * sizeof(vts_tmap_t);
   
@@ -1161,17 +1211,17 @@
     ifofile->vts_tmapt = NULL;
     return 0;
   }
+
   memset(vts_tmapt->tmap, 0, info_length); /* So ifoFree_VTS_TMAPT works. */
   
   for(i = 0; i < vts_tmapt->nr_of_tmaps; i++) {
     if(!DVDFileSeek_(ifofile->file, offset + vts_tmap_srp[i])) {
-      free(vts_tmap_srp);
       ifoFree_VTS_TMAPT(ifofile);
       return 0;
     }
+
     if(!(DVDReadBytes(ifofile->file, &vts_tmapt->tmap[i], VTS_TMAP_SIZE))) {
       fprintf(stderr, "libdvdread: Unable to read VTS_TMAP.\n");
-      free(vts_tmap_srp);
       ifoFree_VTS_TMAPT(ifofile);
       return 0;
     }
@@ -1188,14 +1238,12 @@
     
     vts_tmapt->tmap[i].map_ent = (map_ent_t *)malloc(info_length);
     if(!vts_tmapt->tmap[i].map_ent) {
-      free(vts_tmap_srp);
       ifoFree_VTS_TMAPT(ifofile);
       return 0;
     }
 
     if(!(DVDReadBytes(ifofile->file, vts_tmapt->tmap[i].map_ent, info_length))) {
       fprintf(stderr, "libdvdread: Unable to read VTS_TMAP_ENT.\n");
-      free(vts_tmap_srp);
       ifoFree_VTS_TMAPT(ifofile);
       return 0;
     }
@@ -1203,7 +1251,6 @@
     for(j = 0; j < vts_tmapt->tmap[i].nr_of_entries; j++)
       B2N_32(vts_tmapt->tmap[i].map_ent[j]);
   }    
-  free(vts_tmap_srp);
   
   return 1;
 }
@@ -1219,6 +1266,7 @@
       if(ifofile->vts_tmapt->tmap[i].map_ent)
 	free(ifofile->vts_tmapt->tmap[i].map_ent);
     free(ifofile->vts_tmapt->tmap);
+    free(ifofile->vts_tmapt->vts_tmap_offset);
     free(ifofile->vts_tmapt);
     ifofile->vts_tmapt = NULL;
   }
@@ -1674,7 +1722,7 @@
   free(data);
   
   for(i = 0; i < pgci_ut->nr_of_lus; i++) {
-    CHECK_ZERO(pgci_ut->lu[i].zero_1);
+    CHECK_ZERO(pgci_ut->lu[i].lang_ext);
     // Maybe this is only defined for v1.1 and later titles?
     /* If the bits in 'lu[i].exists' are enumerated abcd efgh then:
             VTS_x_yy.IFO        VIDEO_TS.IFO
@@ -1836,6 +1884,9 @@
     ifofile->vts_atrt = 0;
     return 0;
   }
+
+  vts_atrt->vts_atrt_offsets = data;   
+
   if(!(DVDReadBytes(ifofile->file, data, info_length))) {
     free(data);
     free(vts_atrt);
@@ -1870,7 +1921,6 @@
     assert(offset + vts_atrt->vts[i].last_byte <= vts_atrt->last_byte + 1);
     // Is this check correct?
   }
-  free(data);
 
   return 1;
 }
@@ -1882,6 +1932,7 @@
   
   if(ifofile->vts_atrt) {
     free(ifofile->vts_atrt->vts);
+    free(ifofile->vts_atrt->vts_atrt_offsets);
     free(ifofile->vts_atrt);
     ifofile->vts_atrt = 0;
   }
diff -ur dvdread.old/ifo_types.h dvdread/ifo_types.h
--- dvdread.old/ifo_types.h	Sun Aug 18 08:19:51 2002
+++ dvdread/ifo_types.h	Fri Aug 23 18:56:57 2002
@@ -83,7 +83,8 @@
   
   unsigned int line21_cc_1          : 1;
   unsigned int line21_cc_2          : 1;
-  unsigned int unknown1             : 2;
+  unsigned int unknown1             : 1;
+  unsigned int bit_rate             : 1;
   
   unsigned int picture_size         : 2;
   unsigned int letterboxed          : 1;
@@ -98,14 +99,15 @@
   unsigned int letterboxed          : 1;
   unsigned int picture_size         : 2;
   
-  unsigned int unknown1             : 2;
+  unsigned int bit_rate		    : 1;
+  unsigned int unknown1             : 1;
   unsigned int line21_cc_2          : 1;
   unsigned int line21_cc_1          : 1;
 #endif
 } ATTRIBUTE_PACKED video_attr_t;
 
 /**
- * Audio Attributes. (Incomplete/Wrong?)
+ * Audio Attributes. 
  */
 typedef struct {
 #ifdef WORDS_BIGENDIAN
@@ -132,11 +134,42 @@
   uint16_t lang_code;
   uint8_t  lang_code2; // ??
   uint8_t  lang_extension;
-  uint16_t unknown2;
+/* The first byte (bigendian) i.e. bit 15-8 is reserved/unknown
+   The last byte is either karaoke or surround info depending on
+   application_mode setting
+
+  if (application_mode == karaoke ) {
+   Bit 7 - unknown/reserved
+   Bit 6,5,4 - Karaoke channel assignment
+    0 == Not valid 1+1
+    1 == Not valid 1/0
+    2 == 2/0 L,R
+    3 == 3/0 L,M,R
+    4 == 2/1 L,R,V1
+    5 == 3/1 L,M,R,V1
+    6 == 2/2 L,R,V1,V2
+    7 == 3/2 L,M,R,V1,V2
+   Bit 3,2 - Karaoke version ?? values
+   Bit 1 - MC intro present
+    probably 0 == true, 1 == false
+   Bit 0 - Karaoke mode
+    0 == solo
+    1 == duet
+  } else if ( application_mode == surround ) {
+   Bit 7->4 - reserved/unknown
+   Bit 3 - suitable for surround decoding or not
+   0 == not suitable
+   1 == suitable
+  Bit 2->0 reserved/unknown
+ }
+
+*/
+  uint16_t surround_karaoke;
+
 } ATTRIBUTE_PACKED audio_attr_t;
 
 /**
- * Subpicture Attributes.(Incomplete/Wrong)
+ * Subpicture Attributes.
  */
 typedef struct {
   /*
@@ -149,11 +182,23 @@
    * language: indicates language if type == 1
    * lang extension: if type == 1 contains the lang extension
    */
-  uint8_t type;
+
+#ifdef WORDS_BIGENDIAN
+  unsigned int code_mode :3;
+  unsigned int zero3     :3;
+  unsigned int type      :2;
+#else
+  unsigned int type      :2;
+  unsigned int zero3     :3;
+  unsigned int code_mode :3;
+#endif
+
+
   uint8_t zero1;
   uint16_t lang_code;
   uint8_t lang_extension;
-  uint8_t zero2;
+  uint8_t subp_code_ext;
+
 } ATTRIBUTE_PACKED subp_attr_t;
 
 
@@ -361,7 +406,7 @@
  */
 typedef struct {
   uint16_t lang_code;
-  uint8_t  zero_1;
+  uint8_t  lang_ext;
   uint8_t  exists;
   uint32_t lang_start_byte;
   pgcit_t *pgcit;
@@ -516,7 +561,7 @@
   uint16_t zero_1;
   uint16_t pf_ptl_mai_start_byte;
   uint16_t zero_2;
-  /* uint16_t *pf_ptl_mai // table of nr_of_vtss+1 x 8 */
+  uint16_t *pf_ptl_mai; // table of nr_of_vtss+1 x 8 
 } ATTRIBUTE_PACKED ptl_mait_country_t;
 #define PTL_MAIT_COUNTRY_SIZE 8
 
@@ -570,6 +615,7 @@
   uint16_t nr_of_vtss;
   uint16_t zero_1;
   uint32_t last_byte;
+  uint32_t *vts_atrt_offsets; //Table of offsets to each vts_attributes
   vts_attributes_t *vts;
 } ATTRIBUTE_PACKED vts_atrt_t;
 #define VTS_ATRT_SIZE 8
@@ -703,6 +749,7 @@
   uint16_t nr_of_srpts;
   uint16_t zero_1;
   uint32_t last_byte;
+  uint32_t *ttu_offset; //Offset table for each ttu
   ttu_t  *title;
 } ATTRIBUTE_PACKED vts_ptt_srpt_t;
 #define VTS_PTT_SRPT_SIZE 8
@@ -732,6 +779,7 @@
   uint16_t nr_of_tmaps;
   uint16_t zero_1;
   uint32_t last_byte;
+  uint32_t *vts_tmap_offset; //Offset table for each ttu
   vts_tmap_t *tmap;
 } ATTRIBUTE_PACKED vts_tmapt_t;
 #define VTS_TMAPT_SIZE 8
dvdtxt.c (text/x-csrc, 10 KB)
/*
 * Copyright (C) 2002 Olaf Beck <[email protected]>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <inttypes.h>
#include <limits.h>

#include "bswap.h"
#define CHECK_ZERO(arg) \
  if(memcmp(my_friendly_zeros, &arg, sizeof(arg))) { \
    unsigned int i_CZ; \
    fprintf(stderr, "*** Zero check failed in %s:%i\n    for %s = 0x", \
            __FILE__, __LINE__, # arg ); \
    for(i_CZ = 0; i_CZ < sizeof(arg); i_CZ++) \
      fprintf(stderr, "%02x", *((uint8_t *)&arg + i_CZ)); \
    fprintf(stderr, "\n"); \
  }
static const uint8_t my_friendly_zeros[2048];

	typedef struct {
		uint8_t type;
		uint8_t zero;
		uint16_t offset_string;
	
		/* Not part of the entry */
		/* The text sting it self
		   Max 40 chars + 0x09 ending,
		   total max number of chars 
		   is 64k byte!! */
		uint8_t string[41];
		/* Sting or not 
		0 == false, 1 == true */
		int string_pr;
	} it_txt_idcd_t;



int main(int argc, char *argv[]){

        char * provided_title_name=NULL;

	off_t offset;
        off_t boffset;
	int counter;
        int file, i, j, k;
        int flags;
        uint8_t zero;
        uint16_t zero_16;
	uint32_t zero_32;

	uint32_t sector;
        uint32_t byte;
        uint16_t byte2;
	uint16_t titles;
        char lang[3];
        char array[13];
	char string[41];
	uint8_t istring[41];
        uint16_t what[100];
	uint32_t entry_numbers[100]; 
        uint32_t *offsets;
        uint16_t nr_entries;
	uint8_t type;
	uint16_t offset_string;

	it_txt_idcd_t *it_txt_idcd;



        while ((flags = getopt(argc, argv, "n:")) != -1) {
		switch (flags) {
	             case 'n':
                        if(optarg[0]=='-') fprintf(stderr,"ERROR\n");
                        provided_title_name = optarg;
                        break;
                     default:
                        fprintf(stderr,"ERROR\n");
                }
         }

        if ( (file = open(provided_title_name, O_RDONLY)) == -1 ) {
                fprintf(stderr, "Failed to open %s\n", provided_title_name);
                return(0);
        }
 


	offset = 212;

	if (lseek(file, offset, SEEK_SET) != offset ) {
		fprintf(stderr, "Failed to seek VIDEO_TS.IFO\n");
		return(0);
	}


	if ( read(file, &sector, sizeof(sector)) !=  sizeof(sector) ) {
		fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
		return(0);
	}

	B2N_32(sector);
        //printf("TXTDT_MG Sector is %x\n", sector);

	if( sector == 0 ) {
		printf("No text info in this IFO\n");
		close(file);
		exit(1);
	}

	offset = sector * 2048;
        boffset = offset;

        if (lseek(file, offset, SEEK_SET) != offset ) {
                fprintf(stderr, "Failed to seek VIDEO_TS.IFO\n");
                return(0);
        }

        if ( read(file, &array, sizeof(uint8_t) * 14) !=  sizeof(uint8_t) * 14 ) {
                fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
                return(0);
        }

	array[13]='\0';


        printf("Company/Disk Name: %s\n", array);

  	offset = boffset + 0xc; 
       
        if (lseek(file, offset, SEEK_SET) != offset ) {
                fprintf(stderr, "Failed to seek VIDEO_TS.IFO\n");
                return(0);
        }

        if ( read(file, &sector, sizeof(uint32_t)) !=  sizeof(uint32_t)) {
                fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
                return(0);
        }


	B2N_32(sector);

        offsets = (uint32_t *)malloc(sizeof(uint32_t) * sector);


        printf("Number of LU's: %04x\n", sector);



        if ( read(file, &byte, sizeof(uint32_t)) !=  sizeof(uint32_t)) {
                fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
                return(0);
        }


	B2N_32(byte);


        printf("End byte TXTDT_MG: %08x\n", byte);

	for(i=0; i < sector ; i++ ) {


	         if ( read(file, &lang, sizeof(char) * 2) !=  sizeof(char) *2) {
       	         fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
       	         return(0);
       		 }
                 lang[2]='\0';

        

       		 printf("TXTDT_LU nr %d has LANG CODE: %s \n" , i + 1, lang);       
	
       		 if ( read(file, &zero, sizeof(uint8_t)) !=  sizeof(uint8_t)) {
       		         fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
       		         return(0);
       		 }

		CHECK_ZERO(zero);       
   
       		 if ( read(file, &zero, sizeof(uint8_t)) !=  sizeof(uint8_t)) {
       		         fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
       		         return(0);
       		 }

	
       		 printf("TXTDT_LU nr %d has Encoding type: %02x \n" , i + 1, zero);       

       		 if ( read(file, &byte, sizeof(uint32_t)) !=  sizeof(uint32_t)) {
       		         fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
       		         return(0);
       		 }


		B2N_32(byte);

		offsets[i] = byte;
       		printf("TXTDT_LU nr %d start byte is: %08x \n" , i + 1, byte);       


       }

       for(i=0; i < sector ; i++ ) {

	       	 offset = boffset + offsets[i]; 
       
       		 if (lseek(file, offset, SEEK_SET) != offset ) {
       		         fprintf(stderr, "Failed to seek VIDEO_TS.IFO\n");
       		         return(0);
       		 }

       		 if ( read(file, &byte, sizeof(uint32_t)) !=  sizeof(uint32_t)) {
       		         fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
       		         return(0);
       		 }


		B2N_32(byte);

		printf("TXTDT_LU_SRP_nr %d  end byte: %08x\n", i+1, byte);



       		if ( read(file, &what, sizeof(uint16_t) * 100) !=  sizeof(uint16_t)* 100) {
       		         fprintf(stderr, "Faild to read VIDEO_TS.IFO\n");
       		         return(0);
       		}

                for(j=0; j < 100; j++) {
			B2N_16(what[j]);
		}

		/* Now we know that the dist between the start of TXTDT_LU_SRP
                   and the first entry in the TXTDT_LU is 0xCE and we also 
                   know that each entry is 4 bytes hence we can take 
		   "(what[x] - 0xCE)/4" and get a reference number to the entry 
		   we search (I know the mount of "offsets" == tt_srpts + 1
		   but that is not always the truth so we will use the below
		   instead NOTE We add 1 to enable 0 == false i.e. no entry*/

	       for(j=0; j < 100; j++) {
			if( what[j] != 0) {
				entry_numbers[j] = (what[j] - 0xCE)/4 + 1;
				//printf("Entry nr is: %d\n", entry_numbers[j]);
			} else {
			        entry_numbers[j] = 0;
			}
		}


		/* Now we read how many entries we have */

	    	 if ( read(file, &nr_entries, sizeof(uint16_t)) !=  sizeof(uint16_t)) {
       		         fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
       		         return(0);
       		 }


		B2N_16(nr_entries);
		printf("Number of entries is: %d\n", nr_entries);

								
		it_txt_idcd = (it_txt_idcd_t *)malloc(sizeof(it_txt_idcd_t) * nr_entries);	

		 if ( read(file, &zero_16, sizeof(uint16_t)) !=  sizeof(uint16_t)) {
       		         fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
       		         return(0);
       		 }
		B2N_16(zero_16);
		CHECK_ZERO(zero_16);

	
	       
		/* Read all entries */

		for(j=0; j < nr_entries; j++) {

	       
			 if ( read(file, &type, sizeof(uint8_t)) !=  sizeof(uint8_t)) {
       		         	fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
       		         	return(0);
       		 	 }

			 if ( read(file, &zero, sizeof(uint8_t)) !=  sizeof(uint8_t)) {
       		         	fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
       		         	return(0);
       		 	 }

			 if ( read(file, &offset_string, sizeof(uint16_t)) !=  sizeof(uint16_t)) {
       		         	fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
       		         	return(0);
       		 	 }
			 printf("Type is: %02x \n", type);
			 printf("String offset is: %04x \n", offset_string);

			 it_txt_idcd[j].type = type;

			 CHECK_ZERO(zero);

			 B2N_16(offset_string);
			 it_txt_idcd[j].offset_string = offset_string;

			 if (offset_string == 0) {
				it_txt_idcd[j].string_pr = 0;
			 } else {
				it_txt_idcd[j].string_pr = 1;
			}
	       }		

		/* Now we read all stings */
		
		for(j=0; j < nr_entries; j++) {              
			
			  offset = boffset + offsets[i] + 204;
				
 			  if (it_txt_idcd[j].string_pr == 1) {

			        printf("Offset is : %04x\n", offset + it_txt_idcd[j].offset_string);		
       		 		if (lseek(file, offset + it_txt_idcd[j].offset_string, SEEK_SET) != 
						offset + it_txt_idcd[j].offset_string) {

       		         		fprintf(stderr, "Failed to seek VIDEO_TS.IFO\n");
       		         		return(0);
       		 		}


				if ( read(file, it_txt_idcd[j].string, sizeof(uint8_t) * 41) !=  
									sizeof(uint8_t) * 41) {
					fprintf(stderr, "Failed to read VIDEO_TS.IFO\n");
					return(0);
				}

				/* Find "null" i.e. 0x09 in the "string" */
				for(k = 0; k < 41; k++) {
					if(it_txt_idcd[j].string[k] == 0x09) {
						(char)it_txt_idcd[j].string[k] = '\0';
						break;
					}
				}

				printf("The string is %s\n", it_txt_idcd[j].string);
			 }
		}
				

		/* Okay now we have all data lets parse it 
		   very sucky thing since the tables are gigantic */

		/* First of all there is Structure_IDCD types (the type in the it_txt_idcd_t structure) 
		   Structure_IDCD has values from 00h -> 2Fh
                   Then there is Application_IDCD types
		   Application_IDCD has values from 30h -> F0h 
			But I'm to dead now so I leave it for tomorrow :(*/


	       free(it_txt_idcd);
   

       }

       free(offsets);

       close(file);
}
TXTDT.txt (text/plain, 2.5 KB)
/*
 * Copyright (C) 2002 Olaf Beck <[email protected]>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */




This looks something like this

TXTDT_MG Header
TXTDT_MG LU_offsets_info

    TXTDT_LU_SRP Header
    TXTDT_LU_SRP One hundred structure_IDCD pointers (i.e. pointers to entries in the TXT_LU)
       TXT_LU
       TXT_LU entries
       TXT_LU strings




/* Header */

/* 0000 - Company/Disk name identifier 12 bytes */
char ident[12];

Either this:

/* 000c - ??? */

/* 000e - Number of lang units two bytes*/
unit16_t  nr_lang_u;

Or this:

/* 000c - Number of lang units four bytes */
uint32_t nr_lang_u;
//END


/* 0010 - endbyte of VMG_TXT_MG relative to TXTDT_MG*/
uint32_t end_byte;



/* Followed by LU offset/info table most probably */

/* 0000 - TXTDT_LCD Language code first and second char */
unit16_t  langcode; //char one and two

/* 0002 - Reserved/Unknown looks like it's zero all the time */

/* 0003 - Character set
          01 == iso 646 (ASCII)
	  10 == JIS Roman and JIS Kanji1990
	  11 == ISO 8859-1 (Latin 1)
	  12 == JIS Roman and JIS Kanakana including Shift JIS Kanji */
uint8_t   char_set

/* 0004 - txtdt_start_byte Relative to TXTDT_MG*/
uint32_t txtdt_lu_srp_start_byte;




/* TXTDT_LU_SRP Unit ?? */
/* End byte of LU relative to LU */
uint32_t endbyte;

/* Pointers to structure_IDCD in the entry
table relative to TXTDT_LU_SRP
This is in essence pointers to the volume and the
titles present in the volume */
uint16_t structure_IDCD[100];



/* TXTDT_LU */
/* 0000 */
unit16_t nr_of_entries;
/* 0002 */
unit16_t reserved_unknown;

/* Entries */
/* 0000 IT_TXT_IDCD*/
uint8_t  type;

/* 0001 */
uint8_t reserved_unknown;
/* 0002 */
uint16_t offset_to_string_relative_to_TXTDT;

/* Strings */

/* 0000 This is a string holding all text strings separated by
0x09 The max length of the string is 64k byte !! however the max
length of each entry is 40 char*/
char *strings[64k]; IT_TXT
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.