Changes in pnmtoimage if image data are missing
[openjpeg.git] / src / bin / jp2 / convert.c
index a4eb81f6a830e03de16f405d2e375a4dbfbcf6b4..fa02e31c5a458a7d1a7e41b231756bc82d20ad0e 100644 (file)
@@ -580,13 +580,10 @@ struct tga_header {
 };
 #endif /* INFORMATION_ONLY */
 
-static unsigned short get_ushort(const unsigned char *data)
+/* Returns a ushort from a little-endian serialized value */
+static unsigned short get_tga_ushort(const unsigned char *data)
 {
-    unsigned short val = *(const unsigned short *)data;
-#ifdef OPJ_BIG_ENDIAN
-    val = ((val & 0xffU) << 8) | (val >> 8);
-#endif
-    return val;
+    return (unsigned short)(data[0] | (data[1] << 8));
 }
 
 #define TGA_HEADER_SIZE 18
@@ -613,17 +610,17 @@ static int tga_readheader(FILE *fp, unsigned int *bits_per_pixel,
     id_len = tga[0];
     /*cmap_type = tga[1];*/
     image_type = tga[2];
-    /*cmap_index = get_ushort(&tga[3]);*/
-    cmap_len = get_ushort(&tga[5]);
+    /*cmap_index = get_tga_ushort(&tga[3]);*/
+    cmap_len = get_tga_ushort(&tga[5]);
     cmap_entry_size = tga[7];
 
 
 #if 0
-    x_origin = get_ushort(&tga[8]);
-    y_origin = get_ushort(&tga[10]);
+    x_origin = get_tga_ushort(&tga[8]);
+    y_origin = get_tga_ushort(&tga[10]);
 #endif
-    image_w = get_ushort(&tga[12]);
-    image_h = get_ushort(&tga[14]);
+    image_w = get_tga_ushort(&tga[12]);
+    image_h = get_tga_ushort(&tga[14]);
     pixel_depth = tga[16];
     image_desc  = tga[17];
 
@@ -817,6 +814,25 @@ opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters)
         color_space = OPJ_CLRSPC_SRGB;
     }
 
+    /* If the declared file size is > 10 MB, check that the file is big */
+    /* enough to avoid excessive memory allocations */
+    if (image_height != 0 &&
+            image_width > 10000000U / image_height / (OPJ_UINT32)numcomps) {
+        char ch;
+        OPJ_UINT64 expected_file_size =
+            (OPJ_UINT64)image_width * image_height * (OPJ_UINT32)numcomps;
+        long curpos = ftell(f);
+        if (expected_file_size > (OPJ_UINT64)INT_MAX) {
+            expected_file_size = (OPJ_UINT64)INT_MAX;
+        }
+        fseek(f, (long)expected_file_size - 1, SEEK_SET);
+        if (fread(&ch, 1, 1, f) != 1) {
+            fclose(f);
+            return NULL;
+        }
+        fseek(f, curpos, SEEK_SET);
+    }
+
     subsampling_dx = parameters->subsampling_dx;
     subsampling_dy = parameters->subsampling_dy;
 
@@ -1147,6 +1163,7 @@ opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters)
     opj_image_cmptparm_t cmptparm;  /* maximum of 1 component  */
     opj_image_t * image = NULL;
     int adjustS, ushift, dshift, force8;
+    OPJ_UINT64 expected_file_size;
 
     char endian1, endian2, sign;
     char signtmp[32];
@@ -1169,7 +1186,7 @@ opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters)
     }
 
     fseek(f, 0, SEEK_SET);
-    if (fscanf(f, "PG%[ \t]%c%c%[ \t+-]%d%[ \t]%d%[ \t]%d", temp, &endian1,
+    if (fscanf(f, "PG%31[ \t]%c%c%31[ \t+-]%d%31[ \t]%d%31[ \t]%d", temp, &endian1,
                &endian2, signtmp, &prec, temp, &w, temp, &h) != 9) {
         fclose(f);
         fprintf(stderr,
@@ -1197,6 +1214,29 @@ opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters)
         return NULL;
     }
 
+    if (w < 1 || h < 1 || prec < 1 || prec > 31) {
+        fclose(f);
+        fprintf(stderr, "Bad pgx header, please check input file\n");
+        return NULL;
+    }
+
+    expected_file_size =
+        (OPJ_UINT64)w * (OPJ_UINT64)h * (prec > 16 ? 4 : prec > 8 ? 2 : 1);
+    if (expected_file_size > 10000000U) {
+        char ch;
+        long curpos = ftell(f);
+        if (expected_file_size > (OPJ_UINT64)INT_MAX) {
+            expected_file_size = (OPJ_UINT64)INT_MAX;
+        }
+        fseek(f, (long)expected_file_size - 1, SEEK_SET);
+        if (fread(&ch, 1, 1, f) != 1) {
+            fprintf(stderr, "File too short\n");
+            fclose(f);
+            return NULL;
+        }
+        fseek(f, curpos, SEEK_SET);
+    }
+
     /* initialize image component */
 
     cmptparm.x0 = (OPJ_UINT32)parameters->image_offset_x0;
@@ -1292,7 +1332,7 @@ opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters)
     return image;
 }
 
-#define CLAMP(x,a,b) x < a ? a : (x > b ? b : x)
+#define CLAMP(x,a,b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
 
 static INLINE int clamp(const int value, const int prec, const int sgnd)
 {
@@ -1372,25 +1412,62 @@ int imagetopgx(opj_image_t * image, const char *outfile)
             nbytes = 4;
         }
 
-        for (i = 0; i < w * h; i++) {
-            /* FIXME: clamp func is being called within a loop */
-            const int val = clamp(image->comps[compno].data[i],
-                                  (int)comp->prec, (int)comp->sgnd);
-
-            for (j = nbytes - 1; j >= 0; j--) {
-                int v = (int)(val >> (j * 8));
-                unsigned char byte = (unsigned char)v;
-                res = fwrite(&byte, 1, 1, fdest);
-
-                if (res < 1) {
-                    fprintf(stderr, "failed to write 1 byte for %s\n", name);
+        if (nbytes == 1) {
+            unsigned char* line_buffer = malloc((size_t)w);
+            if (line_buffer == NULL) {
+                fprintf(stderr, "Out of memory");
+                if (total > 256) {
+                    free(name);
+                }
+                goto fin;
+            }
+            for (j = 0; j < h; j++) {
+                if (comp->prec == 8 && comp->sgnd == 0) {
+                    for (i = 0; i < w; i++) {
+                        line_buffer[i] = (unsigned char)CLAMP(image->comps[compno].data[j * w + i], 0,
+                                                              255);
+                    }
+                } else {
+                    for (i = 0; i < w; i++) {
+                        line_buffer[i] = (unsigned char)
+                                         clamp(image->comps[compno].data[j * w + i],
+                                               (int)comp->prec, (int)comp->sgnd);
+                    }
+                }
+                res = fwrite(line_buffer, 1, (size_t)w, fdest);
+                if (res != (size_t)w) {
+                    fprintf(stderr, "failed to write %d bytes for %s\n", w, name);
                     if (total > 256) {
                         free(name);
                     }
+                    free(line_buffer);
                     goto fin;
                 }
             }
+            free(line_buffer);
+        } else {
+
+            for (i = 0; i < w * h; i++) {
+                /* FIXME: clamp func is being called within a loop */
+                const int val = clamp(image->comps[compno].data[i],
+                                      (int)comp->prec, (int)comp->sgnd);
+
+                for (j = nbytes - 1; j >= 0; j--) {
+                    int v = (int)(val >> (j * 8));
+                    unsigned char byte = (unsigned char)v;
+                    res = fwrite(&byte, 1, 1, fdest);
+
+                    if (res < 1) {
+                        fprintf(stderr, "failed to write 1 byte for %s\n", name);
+                        if (total > 256) {
+                            free(name);
+                        }
+                        goto fin;
+                    }
+                }
+            }
         }
+
         if (total > 256) {
             free(name);
         }
@@ -1735,6 +1812,13 @@ opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters)
         return NULL;
     }
 
+    if (header_info.width == 0
+            || header_info.height == 0
+            || (header_info.format == 7 && header_info.depth == 0)) {
+        fclose(fp);
+        return NULL;
+    }
+
     /* This limitation could be removed by making sure to use size_t below */
     if (header_info.height != 0 &&
             header_info.width > INT_MAX / header_info.height) {
@@ -1820,8 +1904,10 @@ opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters)
             for (compno = 0; compno < numcomps; compno++) {
                 index = 0;
                 if (fscanf(fp, "%u", &index) != 1) {
-                    fprintf(stderr,
-                            "\nWARNING: fscanf return a number of element different from the expected.\n");
+                    fprintf(stderr, "Missing data. Quitting.\n");
+                    opj_image_destroy(image);
+                    fclose(fp);
+                    return NULL;
                 }
 
                 image->comps[compno].data[i] = (OPJ_INT32)(index * 255) / header_info.maxval;
@@ -1839,8 +1925,7 @@ opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters)
         for (i = 0; i < w * h; i++) {
             for (compno = 0; compno < numcomps; compno++) {
                 if (!fread(&c0, 1, 1, fp)) {
-                    fprintf(stderr,
-                            "\nError: fread return a number of element different from the expected.\n");
+                    fprintf(stderr, "Missing data. Quitting.\n");
                     opj_image_destroy(image);
                     fclose(fp);
                     return NULL;
@@ -1849,8 +1934,10 @@ opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters)
                     image->comps[compno].data[i] = c0;
                 } else {
                     if (!fread(&c1, 1, 1, fp)) {
-                        fprintf(stderr,
-                                "\nError: fread return a number of element different from the expected.\n");
+                        fprintf(stderr, "Missing data. Quitting.\n");
+                        opj_image_destroy(image);
+                        fclose(fp);
+                        return NULL;
                     }
                     /* netpbm: */
                     image->comps[compno].data[i] = ((c0 << 8) | c1);
@@ -1862,15 +1949,17 @@ opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters)
             unsigned int index;
 
             if (fscanf(fp, "%u", &index) != 1) {
-                fprintf(stderr,
-                        "\nWARNING: fscanf return a number of element different from the expected.\n");
+                fprintf(stderr, "Missing data. Quitting.\n");
+                opj_image_destroy(image);
+                fclose(fp);
+                return NULL;
             }
 
             image->comps[0].data[i] = (index ? 0 : 255);
         }
     } else if (format == 4) {
         int x, y, bit;
-        unsigned char uc;
+        int uc;
 
         i = 0;
         for (y = 0; y < h; ++y) {
@@ -1880,9 +1969,15 @@ opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters)
             for (x = 0; x < w; ++x) {
                 if (bit == -1) {
                     bit = 7;
-                    uc = (unsigned char)getc(fp);
+                    uc = getc(fp);
+                    if (uc == EOF) {
+                        fprintf(stderr, "Missing data. Quitting.\n");
+                        opj_image_destroy(image);
+                        fclose(fp);
+                        return NULL;
+                    }
                 }
-                image->comps[0].data[i] = (((uc >> bit) & 1) ? 0 : 255);
+                image->comps[0].data[i] = ((((unsigned char)uc >> bit) & 1) ? 0 : 255);
                 --bit;
                 ++i;
             }
@@ -1892,8 +1987,10 @@ opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters)
 
         for (i = 0; i < w * h; ++i) {
             if (!fread(&uc, 1, 1, fp)) {
-                fprintf(stderr,
-                        "\nError: fread return a number of element different from the expected.\n");
+                fprintf(stderr, "Missing data. Quitting.\n");
+                opj_image_destroy(image);
+                fclose(fp);
+                return NULL;
             }
             image->comps[0].data[i] = (uc & 1) ? 0 : 255;
         }