tool to fixes some issues in baseline tiffs (with extensions), see http://andreas-romeyke.de
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

244 lines
8.7 KiB

  1. /* fixes broken TIFF Files
  2. *
  3. * fixes invalid DateTime-field in Baseline-TIFFs,
  4. * based on http://www.awaresystems.be/imaging/tiff/tifftags/baseline.html
  5. *
  6. * author: Andreas Romeyke, 2013
  7. * licensed under conditions of libtiff
  8. */
  9. #include "fixit_tiff.h"
  10. #include "check_datetime.h"
  11. #include "tiff_helper.h"
  12. /** RULE0: default rule (string is correct) */
  13. static int rule_default (const char * datestring, int * year, int * month, int * day, int * hour, int * min, int * sec) {
  14. if (FLAGGED == flag_be_verbose) printf ("rule00\n");
  15. if (6 == sscanf(datestring, "%04d:%02d:%02d%02d:%02d:%02d", year, month, day, hour, min, sec)) {
  16. return test_plausibility(year, month, day, hour, min, sec);
  17. } else {
  18. return -2;
  19. }
  20. }
  21. /** RULE1: fix: '18.03.2010 09:59:17' => '2010:03:18 09:59:17' */
  22. static int rule_ddmmyyhhmmss_01 (const char * datestring, int * year, int * month, int * day, int * hour, int * min, int * sec) {
  23. if (FLAGGED == flag_be_verbose) printf ("rule01\n");
  24. if (6 == sscanf(datestring, "%02d.%02d.%04d%02d:%02d:%02d", day, month, year, hour, min, sec)) {
  25. return test_plausibility(year, month, day, hour, min, sec);
  26. } else {
  27. return -2;
  28. }
  29. }
  30. /** RULE2: fix: '2010-03-18 09:59:17' => '2010:03:18 09:59:17' */
  31. static int rule_ddmmyyhhmmss_02 (const char * datestring, int * year, int * month, int * day, int * hour, int * min, int * sec) {
  32. if (FLAGGED == flag_be_verbose) printf ("rule02\n");
  33. if (6 == sscanf(datestring, "%04d-%02d-%02d%02d:%02d:%02d", year, month, day , hour, min, sec)) {
  34. return test_plausibility(year, month, day, hour, min, sec);
  35. } else {
  36. return -2;
  37. }
  38. }
  39. /** RULE3: fix 'Tue Dec 19 09:18:54 2006%0A' => '2006:12:19 09:18:45' */
  40. static int rule_ddmmyyhhmmss_03 (const char * datestring, int * year, int * month, int * day, int * hour, int * min, int * sec) {
  41. if (FLAGGED == flag_be_verbose) printf ("rule03\n");
  42. char dow[4] = "\0\0\0\0";
  43. char monthstring[4] = "\0\0\0\0";
  44. static char* months[] = {
  45. "Jan",
  46. "Feb",
  47. "Mar",
  48. "Apr",
  49. "May",
  50. "Jun",
  51. "Jul",
  52. "Aug",
  53. "Sep",
  54. "Oct",
  55. "Nov",
  56. "Dec"
  57. };
  58. fprintf (stderr, "Datestring '%s'\n", datestring);
  59. int ret = 0;
  60. ret = sscanf(datestring, "%3s%3s%02d%02d:%02d:%02d%04d", dow, monthstring, day, hour, min, sec, year);
  61. if (7 == ret ) {
  62. *month=-1;
  63. for (int i = 0; i<= 11; i++) {
  64. if (strncmp (months[i], monthstring, 3) == 0) {
  65. *month=i+1;
  66. break;
  67. }
  68. }
  69. return test_plausibility(year, month, day, hour, min, sec);
  70. } else {
  71. return -2;
  72. }
  73. }
  74. /** RULENOFIX: dummy rule if no other rule matches, calls only exit */
  75. static int rule_nofix (const char * datestring, int * year, int * month, int * day, int * hour, int * min, int * sec) {
  76. fprintf(stderr, "rule nofix, there is no applyable rule left, aborted without fixing problem\n");
  77. exit(FIXIT_TIFF_DATETIME_RULE_NOT_FOUND);
  78. }
  79. /** used for array of rules */
  80. #define COUNT_OF_RULES 5
  81. /** Array of rules */
  82. int (*rules_ptr[COUNT_OF_RULES])(const char *, int *, int *, int *, int *, int *, int *) = {
  83. rule_default,
  84. rule_ddmmyyhhmmss_01,
  85. rule_ddmmyyhhmmss_02,
  86. rule_ddmmyyhhmmss_03,
  87. rule_nofix
  88. };
  89. /** corrects broken date string to expected format, see
  90. * http://www.awaresystems.be/imaging/tiff/tifftags/datetime.html
  91. * @param broken_datetime string with wrong datetime
  92. * @return string with corrected datetime
  93. */
  94. char * correct_datestring (const char * broken_datetime) {
  95. int day;
  96. int month;
  97. int year;
  98. int hour;
  99. int min;
  100. int sec;
  101. /* if ret is wrong, you could try another rules to apply */
  102. int r;
  103. for (r = 0; r < COUNT_OF_RULES; r++) {
  104. if (FLAGGED == flag_be_verbose) printf("Applying rule%i", r);
  105. if (0 != (*rules_ptr[r])(broken_datetime, &year, &month, &day, &hour, &min, &sec)) {
  106. if (FLAGGED == flag_be_verbose) printf("applying next rule\n");
  107. } else {
  108. break;
  109. }
  110. }
  111. if (FLAGGED == flag_be_verbose) printf("datetime parsing of string '%s', year=%04d, month=%02d, day=%02d, hour=%02d, min=%02d, sec=%02d\n", broken_datetime, year, month, day, hour, min, sec);
  112. /* write corrected value to new string */
  113. char * fixed_date = malloc(sizeof(char) * TIFFDATETIMELENGTH); /* 20 comes from TIFF definition */
  114. if (NULL == fixed_date) {
  115. fprintf(stderr, "could not allocate memory for datetime conversion, abort\n");
  116. exit (FIXIT_TIFF_MEMORY_ALLOCATION_ERROR);
  117. }
  118. int written = snprintf(fixed_date, TIFFDATETIMELENGTH, "%04d:%02d:%02d %02d:%02d:%02d", year, month, day, hour, min, sec);
  119. if (written != (TIFFDATETIMELENGTH)-1) {
  120. fprintf(stderr, "something wrong, instead %d chars, %d chars were written\n",TIFFDATETIMELENGTH-1 ,written);
  121. exit (FIXIT_TIFF_STRING_COPY_ERROR);
  122. }
  123. return fixed_date;
  124. }
  125. /** loads a tiff, fix it if needed, stores tiff
  126. * @param filename filename which should be processed, repaired
  127. */
  128. int cleanup_datetime(const char * filename ) {
  129. if (FIXIT_TIFF_IS_VALID == check_datetime(filename)) return FIXIT_TIFF_IS_VALID;
  130. else {
  131. /* load file */
  132. TIFF* tif = TIFFOpen(filename, "r+");
  133. if (NULL == tif) {
  134. fprintf( stderr, "file '%s' could not be opened\n", filename);
  135. exit (FIXIT_TIFF_READ_PERMISSION_ERROR);
  136. };
  137. /* find date-tag and fix it */
  138. char *datetime=NULL;
  139. uint32 tag_counter=TIFFGetRawTagListCount(tif);
  140. uint32 tagidx;
  141. for (tagidx=0; tagidx < tag_counter; tagidx++) {
  142. uint32 tag = TIFFGetRawTagListEntry( tif, tagidx );
  143. if (tag == TIFFTAG_DATETIME) {
  144. /* via TIFFGetRawTagListEntry we have the tag
  145. * read, the next 2 bytes are the type, next 2 count, last 4 value/offset */
  146. int fd = TIFFFileno( tif);
  147. uint16 tagtype=0;
  148. if ( read( fd, &tagtype, 2) != 2 ) {
  149. perror ("TIFF Header read error tagtype");
  150. exit( FIXIT_TIFF_READ_ERROR );
  151. }
  152. if (TIFFIsByteSwapped(tif))
  153. TIFFSwabShort(&tagtype);
  154. assert(TIFF_ASCII == tagtype);
  155. uint32 bytepos_count = lseek( fd, 0, SEEK_CUR );
  156. uint32 count=0;
  157. if ( read( fd, &count, 4) != 4 ) {
  158. perror ("TIFF Header read error tagcount");
  159. exit( FIXIT_TIFF_READ_ERROR );
  160. }
  161. if (TIFFIsByteSwapped(tif))
  162. TIFFSwabLong(&count);
  163. uint32 offset=0;
  164. if ( read( fd, &offset, 4) != 4 ) {
  165. perror ("TIFF Header read error offset");
  166. exit( FIXIT_TIFF_READ_ERROR );
  167. }
  168. if (TIFFIsByteSwapped(tif))
  169. TIFFSwabLong(&offset);
  170. if (FLAGGED == flag_be_verbose) printf("tag=%u tagtype=%i c=%u offset=%u\n", tag, tagtype, count, offset);
  171. datetime = malloc( sizeof( char ) * count);
  172. if (NULL == datetime) {
  173. perror("Could not allocate memory for new datetime");
  174. exit(FIXIT_TIFF_MEMORY_ALLOCATION_ERROR);
  175. }
  176. /* rewind to offset */
  177. if (lseek(fd, offset, SEEK_SET) != offset) {
  178. perror("TIFF datetime seek error to offset");
  179. exit( FIXIT_TIFF_READ_ERROR );
  180. }
  181. if (read(fd, datetime, count) != count) {
  182. perror ("TIFF datetime read error offset");
  183. exit( FIXIT_TIFF_READ_ERROR );
  184. }
  185. /* repair */
  186. char * new_datetime = correct_datestring( datetime );
  187. if (NULL == new_datetime) {
  188. perror("Could not allocate memory for new datetime");
  189. exit(FIXIT_TIFF_MEMORY_ALLOCATION_ERROR);
  190. }
  191. /* rewind to offset */
  192. if (lseek(fd, offset, SEEK_SET) != offset) {
  193. perror("TIFF datetime seek error to offset");
  194. exit( FIXIT_TIFF_READ_ERROR );
  195. }
  196. /* write data back, only if no flag_check_only is set */
  197. if (write(fd, new_datetime, TIFFDATETIMELENGTH) != TIFFDATETIMELENGTH) {
  198. perror("TIFF datetime write error");
  199. exit(FIXIT_TIFF_WRITE_ERROR);
  200. }
  201. /* rewind to IFD to set count */
  202. if (lseek(fd, bytepos_count, SEEK_SET) != bytepos_count) {
  203. perror("TIFF datetime seek error to IFD pos");
  204. exit( FIXIT_TIFF_READ_ERROR );
  205. }
  206. /* write corrected count, only if no flag_check_only is set */
  207. count = TIFFDATETIMELENGTH;
  208. if (TIFFIsByteSwapped(tif))
  209. TIFFSwabLong(&count);
  210. if (write(fd, &count, 4) != 4) {
  211. perror("TIFF datetime write error IFD count for datetime");
  212. exit(FIXIT_TIFF_WRITE_ERROR);
  213. }
  214. TIFFClose(tif);
  215. if (FLAGGED == flag_be_verbose) {
  216. printf("tag=%u tagtype=%i count=%u offset=%u (0x%04x)\n", tag, tagtype, count, offset, offset);
  217. printf("old_datetime='%s'\n", datetime);
  218. printf("new_datretime='%s'\n", new_datetime);
  219. printf("\n");
  220. }
  221. free(new_datetime);
  222. break;
  223. }
  224. if (FLAGGED == flag_be_verbose) printf("After correction\n-----------------\n");
  225. }
  226. }
  227. if (FIXIT_TIFF_IS_VALID == check_datetime (filename)) return FIXIT_TIFF_IS_CORRECTED;
  228. else return FIXIT_TIFF_IS_CHECKED;
  229. }