"Fossies" - the Fresh Open Source Software Archive

Member "jhead-3.04/jpgfile.c" (22 Nov 2019, 24825 Bytes) of package /linux/privat/jhead-3.04.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "jpgfile.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.03_vs_3.04.

    1 //--------------------------------------------------------------------------
    2 // Program to pull the information out of various types of EXIF digital 
    3 // camera files and show it in a reasonably consistent way
    4 //
    5 // This module handles basic Jpeg file handling
    6 //
    7 // Matthias Wandel
    8 //--------------------------------------------------------------------------
    9 #include "jhead.h"
   10 
   11 // Storage for simplified info extracted from file.
   12 ImageInfo_t ImageInfo;
   13 
   14 
   15 static Section_t * Sections = NULL;
   16 static int SectionsAllocated;
   17 static int SectionsRead;
   18 static int HaveAll;
   19 
   20 
   21 
   22 #define PSEUDO_IMAGE_MARKER 0x123; // Extra value.
   23 //--------------------------------------------------------------------------
   24 // Get 16 bits motorola order (always) for jpeg header stuff.
   25 //--------------------------------------------------------------------------
   26 static int Get16m(const void * Short)
   27 {
   28     return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
   29 }
   30 
   31 
   32 //--------------------------------------------------------------------------
   33 // Process a COM marker.
   34 // We want to print out the marker contents as legible text;
   35 // we must guard against random junk and varying newline representations.
   36 //--------------------------------------------------------------------------
   37 static void process_COM (const uchar * Data, int length)
   38 {
   39     int ch;
   40     char Comment[MAX_COMMENT_SIZE+1];
   41     int nch;
   42     int a;
   43 
   44     nch = 0;
   45 
   46     if (length > MAX_COMMENT_SIZE) length = MAX_COMMENT_SIZE; // Truncate if it won't fit in our structure.
   47 
   48     for (a=2;a<length;a++){
   49         ch = Data[a];
   50 
   51         if (ch == '\r' && Data[a+1] == '\n') continue; // Remove cr followed by lf.
   52 
   53         if (ch >= 32 || ch == '\n' || ch == '\t'){
   54             Comment[nch++] = (char)ch;
   55         }else{
   56             Comment[nch++] = '?';
   57         }
   58     }
   59 
   60     Comment[nch] = '\0'; // Null terminate
   61 
   62     if (ShowTags){
   63         printf("COM marker comment: %s\n",Comment);
   64     }
   65 
   66     strcpy(ImageInfo.Comments,Comment);
   67     ImageInfo.CommentWidthchars = 0;
   68 }
   69 
   70  
   71 //--------------------------------------------------------------------------
   72 // Process a SOFn marker.  This is useful for the image dimensions
   73 //--------------------------------------------------------------------------
   74 static void process_SOFn (const uchar * Data, int marker)
   75 {
   76     int data_precision, num_components;
   77 
   78     data_precision = Data[2];
   79     ImageInfo.Height = Get16m(Data+3);
   80     ImageInfo.Width = Get16m(Data+5);
   81     num_components = Data[7];
   82 
   83     if (num_components == 3){
   84         ImageInfo.IsColor = 1;
   85     }else{
   86         ImageInfo.IsColor = 0;
   87     }
   88 
   89     ImageInfo.Process = marker;
   90 
   91     if (ShowTags){
   92         printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
   93                    ImageInfo.Width, ImageInfo.Height, num_components, data_precision);
   94     }
   95 }
   96 
   97 
   98 //--------------------------------------------------------------------------
   99 // Check sections array to see if it needs to be increased in size.
  100 //--------------------------------------------------------------------------
  101 static void CheckSectionsAllocated(void)
  102 {
  103     if (SectionsRead > SectionsAllocated){
  104         ErrFatal("allocation screwup");
  105     }
  106     if (SectionsRead >= SectionsAllocated){
  107         SectionsAllocated += SectionsAllocated/2;
  108         Sections = (Section_t *)realloc(Sections, sizeof(Section_t)*SectionsAllocated);
  109         if (Sections == NULL){
  110             ErrFatal("could not allocate data for entire image");
  111         }
  112     }
  113 }
  114 
  115 
  116 //--------------------------------------------------------------------------
  117 // Parse the marker stream until SOS or EOI is seen;
  118 //--------------------------------------------------------------------------
  119 int ReadJpegSections (FILE * infile, ReadMode_t ReadMode)
  120 {
  121     int a;
  122     int HaveCom = FALSE;
  123 
  124     a = fgetc(infile);
  125 
  126     if (a != 0xff || fgetc(infile) != M_SOI){
  127         return FALSE;
  128     }
  129 
  130     ImageInfo.JfifHeader.XDensity = ImageInfo.JfifHeader.YDensity = 300;
  131     ImageInfo.JfifHeader.ResolutionUnits = 1;
  132 
  133     for(;;){
  134         int itemlen;
  135         int prev;
  136         int marker = 0;
  137         int ll,lh, got;
  138         uchar * Data;
  139 
  140         CheckSectionsAllocated();
  141 
  142         prev = 0;
  143         for (a=0;;a++){
  144             marker = fgetc(infile);
  145             if (marker != 0xff && prev == 0xff) break;
  146             if (marker == EOF){
  147                 ErrFatal("Unexpected end of file");
  148             }
  149             prev = marker;
  150         }
  151 
  152         if (a > 10){
  153             ErrNonfatal("Extraneous %d padding bytes before section %02X",a-1,marker);
  154         }
  155 
  156         Sections[SectionsRead].Type = marker;
  157   
  158         // Read the length of the section.
  159         lh = fgetc(infile);
  160         ll = fgetc(infile);
  161         if (lh == EOF || ll == EOF){
  162             ErrFatal("Unexpected end of file");
  163         }
  164 
  165         itemlen = (lh << 8) | ll;
  166 
  167         if (itemlen < 2){
  168             ErrFatal("invalid marker");
  169         }
  170 
  171         Sections[SectionsRead].Size = itemlen;
  172 
  173         Data = (uchar *)malloc(itemlen);
  174         if (Data == NULL){
  175             ErrFatal("Could not allocate memory");
  176         }
  177         Sections[SectionsRead].Data = Data;
  178 
  179         // Store first two pre-read bytes.
  180         Data[0] = (uchar)lh;
  181         Data[1] = (uchar)ll;
  182 
  183         got = fread(Data+2, 1, itemlen-2, infile); // Read the whole section.
  184         if (got != itemlen-2){
  185             ErrFatal("Premature end of file?");
  186         }
  187         SectionsRead += 1;
  188 
  189         switch(marker){
  190 
  191             case M_SOS:   // stop before hitting compressed data 
  192                 // If reading entire image is requested, read the rest of the data.
  193                 if (ReadMode & READ_IMAGE){
  194                     int cp, ep, size;
  195                     // Determine how much file is left.
  196                     cp = ftell(infile);
  197                     fseek(infile, 0, SEEK_END);
  198                     ep = ftell(infile);
  199                     fseek(infile, cp, SEEK_SET);
  200 
  201                     size = ep-cp;
  202                     Data = (uchar *)malloc(size);
  203                     if (Data == NULL){
  204                         ErrFatal("could not allocate data for entire image");
  205                     }
  206 
  207                     got = fread(Data, 1, size, infile);
  208                     if (got != size){
  209                         ErrFatal("could not read the rest of the image");
  210                     }
  211 
  212                     CheckSectionsAllocated();
  213                     Sections[SectionsRead].Data = Data;
  214                     Sections[SectionsRead].Size = size;
  215                     Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
  216                     SectionsRead ++;
  217                     HaveAll = 1;
  218                 }
  219                 return TRUE;
  220 
  221             case M_DQT:
  222                 // Use for jpeg quality guessing
  223                 process_DQT(Data, itemlen);
  224                 break;
  225 
  226             case M_DHT:   
  227                 // Use for jpeg quality guessing
  228                 process_DHT(Data, itemlen);
  229                 break;
  230 
  231 
  232             case M_EOI:   // in case it's a tables-only JPEG stream
  233                 fprintf(stderr,"No image in jpeg!\n");
  234                 return FALSE;
  235 
  236             case M_COM: // Comment section
  237                 if (HaveCom || ((ReadMode & READ_METADATA) == 0)){
  238                     // Discard this section.
  239                     free(Sections[--SectionsRead].Data);
  240                 }else{
  241                     process_COM(Data, itemlen);
  242                     HaveCom = TRUE;
  243                 }
  244                 break;
  245 
  246             case M_JFIF:
  247                 // Regular jpegs always have this tag, exif images have the exif
  248                 // marker instead, althogh ACDsee will write images with both markers.
  249                 // this program will re-create this marker on absence of exif marker.
  250                 // hence no need to keep the copy from the file.
  251                 if (itemlen < 16){
  252                     fprintf(stderr,"Jfif header too short\n");
  253                     goto ignore;
  254                 }
  255                 if (memcmp(Data+2, "JFIF\0",5)){
  256                     fprintf(stderr,"Header missing JFIF marker\n");
  257                 }
  258 
  259                 ImageInfo.JfifHeader.Present = TRUE;
  260                 ImageInfo.JfifHeader.ResolutionUnits = Data[9];
  261                 ImageInfo.JfifHeader.XDensity = (Data[10]<<8) | Data[11];
  262                 ImageInfo.JfifHeader.YDensity = (Data[12]<<8) | Data[13];
  263                 if (ShowTags){
  264                     printf("JFIF SOI marker: Units: %d ",ImageInfo.JfifHeader.ResolutionUnits);
  265                     switch(ImageInfo.JfifHeader.ResolutionUnits){
  266                         case 0: printf("(aspect ratio)"); break;
  267                         case 1: printf("(dots per inch)"); break;
  268                         case 2: printf("(dots per cm)"); break;
  269                         default: printf("(unknown)"); break;
  270                     }
  271                     printf("  X-density=%d Y-density=%d\n",ImageInfo.JfifHeader.XDensity, ImageInfo.JfifHeader.YDensity);
  272 
  273                     if (Data[14] || Data[15]){
  274                         fprintf(stderr,"Ignoring jfif header thumbnail\n");
  275                     }
  276                 }
  277 
  278                 ignore:
  279 
  280                 free(Sections[--SectionsRead].Data);
  281                 break;
  282 
  283             case M_EXIF:
  284                 // There can be different section using the same marker.
  285                 if (ReadMode & READ_METADATA){
  286                     if (memcmp(Data+2, "Exif", 4) == 0){
  287                         process_EXIF(Data, itemlen);
  288                         break;
  289                     }else if (memcmp(Data+2, "http:", 5) == 0){
  290                         Sections[SectionsRead-1].Type = M_XMP; // Change tag for internal purposes.
  291                         if (ShowTags){
  292                             printf("Image contains XMP section, %d bytes long\n", itemlen);
  293                             if (ShowTags){
  294                                 ShowXmp(Sections[SectionsRead-1]);
  295                             }
  296                         }
  297                         break;
  298                     }
  299                 }
  300                 // Oterwise, discard this section.
  301                 free(Sections[--SectionsRead].Data);
  302                 break;
  303 
  304             case M_IPTC:
  305                 if (ReadMode & READ_METADATA){
  306                     if (ShowTags){
  307                         printf("Image contains IPTC section, %d bytes long\n", itemlen);
  308                     }
  309                     // Note: We just store the IPTC section.  Its relatively straightforward
  310                     // and we don't act on any part of it, so just display it at parse time.
  311                 }else{
  312                     free(Sections[--SectionsRead].Data);
  313                 }
  314                 break;
  315            
  316             case M_SOF0: 
  317             case M_SOF1: 
  318             case M_SOF2: 
  319             case M_SOF3: 
  320             case M_SOF5: 
  321             case M_SOF6: 
  322             case M_SOF7: 
  323             case M_SOF9: 
  324             case M_SOF10:
  325             case M_SOF11:
  326             case M_SOF13:
  327             case M_SOF14:
  328             case M_SOF15:
  329                 if (itemlen < 8){
  330                     fprintf(stderr,"Section too short\n");
  331                     break;
  332                 }
  333                 process_SOFn(Data, marker);
  334                 break;
  335             default:
  336                 // Skip any other sections.
  337                 if (ShowTags){
  338                     printf("Jpeg section marker 0x%02x size %d\n",marker, itemlen);
  339                 }
  340                 break;
  341         }
  342     }
  343     return TRUE;
  344 }
  345 
  346 //--------------------------------------------------------------------------
  347 // Discard read data.
  348 //--------------------------------------------------------------------------
  349 void DiscardData(void)
  350 {
  351     int a;
  352 
  353     for (a=0;a<SectionsRead;a++){
  354         free(Sections[a].Data);
  355     }
  356 
  357     memset(&ImageInfo, 0, sizeof(ImageInfo));
  358     SectionsRead = 0;
  359     HaveAll = 0;
  360 }
  361 
  362 //--------------------------------------------------------------------------
  363 // Read image data.
  364 //--------------------------------------------------------------------------
  365 int ReadJpegFile(const char * FileName, ReadMode_t ReadMode)
  366 {
  367     FILE * infile;
  368     int ret;
  369 
  370     infile = fopen(FileName, "rb"); // Unix ignores 'b', windows needs it.
  371 
  372     if (infile == NULL) {
  373         fprintf(stderr, "can't open '%s'\n", FileName);
  374         return FALSE;
  375     }
  376 
  377 
  378     // Scan the JPEG headers.
  379     ret = ReadJpegSections(infile, ReadMode);
  380     if (!ret){
  381         if (ReadMode == READ_ANY){
  382             // Process any files mode.  Ignore the fact that it's not
  383             // a jpeg file.
  384             ret = TRUE;
  385         }else{
  386             fprintf(stderr,"Not JPEG: %s\n",FileName);
  387         }
  388     }
  389 
  390     fclose(infile);
  391 
  392     if (ret == FALSE){
  393         DiscardData();
  394     }
  395     return ret;
  396 }
  397 
  398 
  399 //--------------------------------------------------------------------------
  400 // Replace or remove exif thumbnail
  401 //--------------------------------------------------------------------------
  402 int SaveThumbnail(char * ThumbFileName)
  403 {
  404     FILE * ThumbnailFile;
  405 
  406     if (ImageInfo.ThumbnailOffset == 0 || ImageInfo.ThumbnailSize == 0){
  407         fprintf(stderr,"Image contains no thumbnail\n");
  408         return FALSE;
  409     }
  410 
  411     if (strcmp(ThumbFileName, "-") == 0){
  412         // A filename of '-' indicates thumbnail goes to stdout.
  413         // This doesn't make much sense under Windows, so this feature is unix only.
  414         ThumbnailFile = stdout;
  415     }else{
  416         ThumbnailFile = fopen(ThumbFileName,"wb");
  417     }
  418 
  419     if (ThumbnailFile){
  420         uchar * ThumbnailPointer;
  421         Section_t * ExifSection;
  422         ExifSection = FindSection(M_EXIF);
  423         ThumbnailPointer = ExifSection->Data+ImageInfo.ThumbnailOffset+8;
  424 
  425         fwrite(ThumbnailPointer, ImageInfo.ThumbnailSize ,1, ThumbnailFile);
  426         fclose(ThumbnailFile);
  427         return TRUE;
  428     }else{
  429         ErrFatal("Could not write thumbnail file");
  430         return FALSE;
  431     }
  432 }
  433 
  434 //--------------------------------------------------------------------------
  435 // Replace or remove exif thumbnail
  436 //--------------------------------------------------------------------------
  437 int ReplaceThumbnail(const char * ThumbFileName)
  438 {
  439     FILE * ThumbnailFile;
  440     int ThumbLen, NewExifSize;
  441     Section_t * ExifSection;
  442     uchar * ThumbnailPointer;
  443 
  444     if (ImageInfo.ThumbnailOffset == 0 || ImageInfo.ThumbnailAtEnd == FALSE){
  445         if (ThumbFileName == NULL){
  446             // Delete of nonexistent thumbnail (not even pointers present)
  447             // No action, no error.
  448             return FALSE;
  449         }
  450 
  451         // Adding or removing of thumbnail is not possible - that would require rearranging
  452         // of the exif header, which is risky, and jhad doesn't know how to do.
  453         fprintf(stderr,"Image contains no thumbnail to replace - add is not possible\n");
  454         return FALSE;
  455     }
  456 
  457     if (ThumbFileName){
  458         ThumbnailFile = fopen(ThumbFileName,"rb");
  459 
  460         if (ThumbnailFile == NULL){
  461             noread:
  462             ErrFatal("Could not read thumbnail file");
  463             return FALSE;
  464         }
  465 
  466         // get length
  467         fseek(ThumbnailFile, 0, SEEK_END);
  468 
  469         ThumbLen = ftell(ThumbnailFile);
  470         fseek(ThumbnailFile, 0, SEEK_SET);
  471 
  472         if (ThumbLen + ImageInfo.ThumbnailOffset > 0x10000-20){
  473             ErrFatal("Thumbnail is too large to insert into exif header");
  474         }
  475     }else{
  476         if (ImageInfo.ThumbnailSize == 0){
  477              return FALSE;
  478         }
  479 
  480         ThumbLen = 0;
  481         ThumbnailFile = NULL;
  482     }
  483 
  484     ExifSection = FindSection(M_EXIF);
  485 
  486     NewExifSize = ImageInfo.ThumbnailOffset+8+ThumbLen;
  487     ExifSection->Data = (uchar *)realloc(ExifSection->Data, NewExifSize);
  488 
  489     ThumbnailPointer = ExifSection->Data+ImageInfo.ThumbnailOffset+8;
  490 
  491     if (ThumbnailFile){
  492         if (fread(ThumbnailPointer, 1, ThumbLen, ThumbnailFile) != ThumbLen){
  493             goto noread;
  494         }
  495         fclose(ThumbnailFile);
  496     }
  497 
  498     ImageInfo.ThumbnailSize = ThumbLen;
  499 
  500     Put32u(ExifSection->Data+ImageInfo.ThumbnailSizeOffset+8, ThumbLen);
  501 
  502     ExifSection->Data[0] = (uchar)(NewExifSize >> 8);
  503     ExifSection->Data[1] = (uchar)NewExifSize;
  504     ExifSection->Size = NewExifSize;
  505 
  506     return TRUE;
  507 }
  508 
  509 
  510 //--------------------------------------------------------------------------
  511 // Discard everything but the exif and comment sections.
  512 //--------------------------------------------------------------------------
  513 void DiscardAllButExif(void)
  514 {
  515     Section_t ExifKeeper;
  516     Section_t CommentKeeper;
  517     Section_t IptcKeeper;
  518     Section_t XmpKeeper;
  519     int a;
  520 
  521     memset(&ExifKeeper, 0, sizeof(ExifKeeper));
  522     memset(&CommentKeeper, 0, sizeof(CommentKeeper));
  523     memset(&IptcKeeper, 0, sizeof(IptcKeeper));
  524     memset(&XmpKeeper, 0, sizeof(IptcKeeper));
  525 
  526     for (a=0;a<SectionsRead;a++){
  527         if (Sections[a].Type == M_EXIF && ExifKeeper.Type == 0){
  528            ExifKeeper = Sections[a];
  529         }else if (Sections[a].Type == M_XMP && XmpKeeper.Type == 0){
  530            XmpKeeper = Sections[a];
  531         }else if (Sections[a].Type == M_COM && CommentKeeper.Type == 0){
  532             CommentKeeper = Sections[a];
  533         }else if (Sections[a].Type == M_IPTC && IptcKeeper.Type == 0){
  534             IptcKeeper = Sections[a];
  535         }else{
  536             free(Sections[a].Data);
  537         }
  538     }
  539     SectionsRead = 0;
  540     if (ExifKeeper.Type){
  541         CheckSectionsAllocated();
  542         Sections[SectionsRead++] = ExifKeeper;
  543     }
  544     if (CommentKeeper.Type){
  545         CheckSectionsAllocated();
  546         Sections[SectionsRead++] = CommentKeeper;
  547     }
  548     if (IptcKeeper.Type){
  549         CheckSectionsAllocated();
  550         Sections[SectionsRead++] = IptcKeeper;
  551     }
  552 
  553     if (XmpKeeper.Type){
  554         CheckSectionsAllocated();
  555         Sections[SectionsRead++] = XmpKeeper;
  556     }
  557 }    
  558 
  559 //--------------------------------------------------------------------------
  560 // Write image data back to disk.
  561 //--------------------------------------------------------------------------
  562 void WriteJpegFile(const char * FileName)
  563 {
  564     FILE * outfile;
  565     int a;
  566 
  567     if (!HaveAll){
  568         ErrFatal("Can't write back - didn't read all");
  569     }
  570 
  571     outfile = fopen(FileName,"wb");
  572     if (outfile == NULL){
  573         ErrFatal("Could not open file for write");
  574     }
  575 
  576     // Initial static jpeg marker.
  577     fputc(0xff,outfile);
  578     fputc(0xd8,outfile);
  579     
  580     if (Sections[0].Type != M_EXIF && Sections[0].Type != M_JFIF){
  581         // The image must start with an exif or jfif marker.  If we threw those away, create one.
  582         static uchar JfifHead[18] = {
  583             0xff, M_JFIF,
  584             0x00, 0x10, 'J' , 'F' , 'I' , 'F' , 0x00, 0x01, 
  585             0x01, 0x01, 0x01, 0x2C, 0x01, 0x2C, 0x00, 0x00 
  586         };
  587 
  588         if (ImageInfo.ResolutionUnit == 2 || ImageInfo.ResolutionUnit == 3){
  589             // Use the exif resolution info to fill out the jfif header.
  590             // Usually, for exif images, there's no jfif header, so if wediscard
  591             // the exif header, use info from the exif header for the jfif header.
  592             
  593             ImageInfo.JfifHeader.ResolutionUnits = (char)(ImageInfo.ResolutionUnit-1);
  594             // Jfif is 1 and 2, Exif is 2 and 3 for In and cm respecively
  595             ImageInfo.JfifHeader.XDensity = (int)ImageInfo.xResolution;
  596             ImageInfo.JfifHeader.YDensity = (int)ImageInfo.yResolution;
  597         }
  598 
  599         JfifHead[11] = ImageInfo.JfifHeader.ResolutionUnits;
  600         JfifHead[12] = (uchar)(ImageInfo.JfifHeader.XDensity >> 8);
  601         JfifHead[13] = (uchar)ImageInfo.JfifHeader.XDensity;
  602         JfifHead[14] = (uchar)(ImageInfo.JfifHeader.YDensity >> 8);
  603         JfifHead[15] = (uchar)ImageInfo.JfifHeader.YDensity;
  604         
  605 
  606         fwrite(JfifHead, 18, 1, outfile);
  607 
  608         // use the values from the exif data for the jfif header, if we have found values
  609         if (ImageInfo.ResolutionUnit != 0) { 
  610             // JFIF.ResolutionUnit is {1,2}, EXIF.ResolutionUnit is {2,3}
  611             JfifHead[11] = (uchar)ImageInfo.ResolutionUnit - 1; 
  612         }
  613         if (ImageInfo.xResolution > 0.0 && ImageInfo.yResolution > 0.0) { 
  614             JfifHead[12] = (uchar)((int)ImageInfo.xResolution>>8);
  615             JfifHead[13] = (uchar)((int)ImageInfo.xResolution);
  616 
  617             JfifHead[14] = (uchar)((int)ImageInfo.yResolution>>8);
  618             JfifHead[15] = (uchar)((int)ImageInfo.yResolution);
  619         }
  620     }
  621 
  622 
  623     // Write all the misc sections
  624     for (a=0;a<SectionsRead-1;a++){
  625         fputc(0xff,outfile);
  626         fputc((unsigned char)Sections[a].Type, outfile);
  627         fwrite(Sections[a].Data, Sections[a].Size, 1, outfile);
  628     }
  629 
  630     // Write the remaining image data.
  631     fwrite(Sections[a].Data, Sections[a].Size, 1, outfile);
  632        
  633     fclose(outfile);
  634 }
  635 
  636 
  637 //--------------------------------------------------------------------------
  638 // Check if image has exif header.
  639 //--------------------------------------------------------------------------
  640 Section_t * FindSection(int SectionType)
  641 {
  642     int a;
  643 
  644     for (a=0;a<SectionsRead;a++){
  645         if (Sections[a].Type == SectionType){
  646             return &Sections[a];
  647         }
  648     }
  649     // Could not be found.
  650     return NULL;
  651 }
  652 
  653 //--------------------------------------------------------------------------
  654 // Remove a certain type of section.
  655 //--------------------------------------------------------------------------
  656 int RemoveSectionType(int SectionType)
  657 {
  658     int a;
  659     int retval = FALSE;
  660     for (a=0;a<SectionsRead-1;a++){
  661         if (Sections[a].Type == SectionType){
  662             // Free up this section
  663             free (Sections[a].Data);
  664             // Move succeding sections back by one to close space in array.
  665             memmove(Sections+a, Sections+a+1, sizeof(Section_t) * (SectionsRead-a));
  666             SectionsRead -= 1;
  667             a -= 1;
  668             retval = TRUE;
  669         }
  670     }
  671     return retval;
  672 }
  673 
  674 //--------------------------------------------------------------------------
  675 // Remove sectons not part of image and not exif or comment sections.
  676 //--------------------------------------------------------------------------
  677 int RemoveUnknownSections(void)
  678 {
  679     int a;
  680     int Modified = FALSE;
  681     for (a=0;a<SectionsRead-1;){
  682         switch(Sections[a].Type){
  683             case  M_SOF0:
  684             case  M_SOF1:
  685             case  M_SOF2:
  686             case  M_SOF3:
  687             case  M_SOF5:
  688             case  M_SOF6:
  689             case  M_SOF7:
  690             case  M_SOF9:
  691             case  M_SOF10:
  692             case  M_SOF11:
  693             case  M_SOF13:
  694             case  M_SOF14:
  695             case  M_SOF15:
  696             case  M_SOI:
  697             case  M_EOI:
  698             case  M_SOS:
  699             case  M_JFIF:
  700             case  M_EXIF:
  701             case  M_XMP:
  702             case  M_COM:
  703             case  M_DQT:
  704             case  M_DHT:
  705             case  M_DRI:
  706             case  M_IPTC:
  707                 // keep.
  708                 a++;
  709                 break;
  710             default:
  711                 // Unknown.  Delete.
  712                 free (Sections[a].Data);
  713                 // Move succeding sections back by one to close space in array.
  714                 memmove(Sections+a, Sections+a+1, sizeof(Section_t) * (SectionsRead-a));
  715                 SectionsRead -= 1;
  716                 Modified = TRUE;
  717         }
  718     }
  719     return Modified;
  720 }
  721 
  722 //--------------------------------------------------------------------------
  723 // Add a section (assume it doesn't already exist) - used for 
  724 // adding comment sections and exif sections
  725 //--------------------------------------------------------------------------
  726 Section_t * CreateSection(int SectionType, unsigned char * Data, int Size)
  727 {
  728     Section_t * NewSection;
  729     int a;
  730     int NewIndex;
  731 
  732     NewIndex = 0; // Figure out where to put the comment section.
  733     if (SectionType == M_EXIF){
  734         // Exif alwas goes first!
  735     }else{
  736         for (;NewIndex < 3;NewIndex++){ // Maximum fourth position (just for the heck of it)
  737             if (Sections[NewIndex].Type == M_JFIF) continue; // Put it after Jfif
  738             if (Sections[NewIndex].Type == M_EXIF) continue; // Put it after Exif
  739             break;
  740         }
  741     }
  742 
  743     if (SectionsRead < NewIndex){
  744         ErrFatal("Too few sections!");
  745     }
  746 
  747     CheckSectionsAllocated();
  748     for (a=SectionsRead;a>NewIndex;a--){
  749         Sections[a] = Sections[a-1];          
  750     }
  751     SectionsRead += 1;
  752 
  753     NewSection = Sections+NewIndex;
  754 
  755     NewSection->Type = SectionType;
  756     NewSection->Size = Size;
  757     NewSection->Data = Data;
  758 
  759     return NewSection;
  760 }
  761 
  762 
  763 //--------------------------------------------------------------------------
  764 // Initialisation.
  765 //--------------------------------------------------------------------------
  766 void ResetJpgfile(void)
  767 {
  768     if (Sections == NULL){
  769         Sections = (Section_t *)malloc(sizeof(Section_t)*5);
  770         SectionsAllocated = 5;
  771     }
  772 
  773     SectionsRead = 0;
  774     HaveAll = 0;
  775 }