IMG_xpm.c
changeset 443 ee17b8eb58ce
parent 369 35beff028453
child 451 48116d511e5d
equal deleted inserted replaced
442:0f2ca21b7828 443:ee17b8eb58ce
   105     struct color_hash *hash;
   105     struct color_hash *hash;
   106 
   106 
   107     /* we know how many entries we need, so we can allocate
   107     /* we know how many entries we need, so we can allocate
   108        everything here */
   108        everything here */
   109     hash = (struct color_hash *)SDL_malloc(sizeof *hash);
   109     hash = (struct color_hash *)SDL_malloc(sizeof *hash);
   110     if(!hash)
   110     if (!hash)
   111         return NULL;
   111         return NULL;
   112 
   112 
   113     /* use power-of-2 sized hash table for decoding speed */
   113     /* use power-of-2 sized hash table for decoding speed */
   114     for(s = STARTING_HASH_SIZE; s < maxnum; s <<= 1)
   114     for (s = STARTING_HASH_SIZE; s < maxnum; s <<= 1)
   115         ;
   115         ;
   116     hash->size = s;
   116     hash->size = s;
   117     hash->maxnum = maxnum;
   117     hash->maxnum = maxnum;
   118     bytes = hash->size * sizeof(struct hash_entry **);
   118     bytes = hash->size * sizeof(struct hash_entry **);
   119     hash->entries = NULL;   /* in case malloc fails */
   119     hash->entries = NULL;   /* in case malloc fails */
   120     hash->table = (struct hash_entry **)SDL_malloc(bytes);
   120     hash->table = (struct hash_entry **)SDL_malloc(bytes);
   121     if(!hash->table) {
   121     if (!hash->table) {
   122         SDL_free(hash);
   122         SDL_free(hash);
   123         return NULL;
   123         return NULL;
   124     }
   124     }
   125     memset(hash->table, 0, bytes);
   125     memset(hash->table, 0, bytes);
   126     hash->entries = (struct hash_entry *)SDL_malloc(maxnum * sizeof(struct hash_entry));
   126     hash->entries = (struct hash_entry *)SDL_malloc(maxnum * sizeof(struct hash_entry));
   127     if(!hash->entries) {
   127     if (!hash->entries) {
   128         SDL_free(hash->table);
   128         SDL_free(hash->table);
   129         SDL_free(hash);
   129         SDL_free(hash);
   130         return NULL;
   130         return NULL;
   131     }
   131     }
   132     hash->next_free = hash->entries;
   132     hash->next_free = hash->entries;
   149 #define QUICK_COLORHASH(hash, key) ((hash)->table[*(Uint8 *)(key)]->color)
   149 #define QUICK_COLORHASH(hash, key) ((hash)->table[*(Uint8 *)(key)]->color)
   150 
   150 
   151 static Uint32 get_colorhash(struct color_hash *hash, const char *key, int cpp)
   151 static Uint32 get_colorhash(struct color_hash *hash, const char *key, int cpp)
   152 {
   152 {
   153     struct hash_entry *entry = hash->table[hash_key(key, cpp, hash->size)];
   153     struct hash_entry *entry = hash->table[hash_key(key, cpp, hash->size)];
   154     while(entry) {
   154     while (entry) {
   155         if(SDL_memcmp(key, entry->key, cpp) == 0)
   155         if (SDL_memcmp(key, entry->key, cpp) == 0)
   156             return entry->color;
   156             return entry->color;
   157         entry = entry->next;
   157         entry = entry->next;
   158     }
   158     }
   159     return 0;       /* garbage in - garbage out */
   159     return 0;       /* garbage in - garbage out */
   160 }
   160 }
   161 
   161 
   162 static void free_colorhash(struct color_hash *hash)
   162 static void free_colorhash(struct color_hash *hash)
   163 {
   163 {
   164     if(hash) {
   164     if (hash) {
   165         if(hash->table)
   165         if (hash->table)
   166             SDL_free(hash->table);
   166             SDL_free(hash->table);
   167         if(hash->entries)
   167         if (hash->entries)
   168             SDL_free(hash->entries);
   168             SDL_free(hash->entries);
   169         SDL_free(hash);
   169         SDL_free(hash);
   170     }
   170     }
   171 }
   171 }
   172 
   172 
   865         { "yellowgreen",          0x9acd32 },
   865         { "yellowgreen",          0x9acd32 },
   866 #endif /* EXTENDED_XPM_COLORS */
   866 #endif /* EXTENDED_XPM_COLORS */
   867         {"none",                  0xFFFFFF}
   867         {"none",                  0xFFFFFF}
   868     };
   868     };
   869 
   869 
   870     if(spec[0] == '#') {
   870     if (spec[0] == '#') {
   871         char buf[7];
   871         char buf[7];
   872         switch(speclen) {
   872         switch(speclen) {
   873         case 4:
   873         case 4:
   874             buf[0] = buf[1] = spec[1];
   874             buf[0] = buf[1] = spec[1];
   875             buf[2] = buf[3] = spec[2];
   875             buf[2] = buf[3] = spec[2];
   890         buf[6] = '\0';
   890         buf[6] = '\0';
   891         *rgb = strtol(buf, NULL, 16);
   891         *rgb = strtol(buf, NULL, 16);
   892         return 1;
   892         return 1;
   893     } else {
   893     } else {
   894         int i;
   894         int i;
   895         for(i = 0; i < SDL_arraysize(known); i++)
   895         for (i = 0; i < SDL_arraysize(known); i++)
   896             if(SDL_strncasecmp(known[i].name, spec, speclen) == 0) {
   896             if (SDL_strncasecmp(known[i].name, spec, speclen) == 0) {
   897                 *rgb = known[i].rgb;
   897                 *rgb = known[i].rgb;
   898                 return 1;
   898                 return 1;
   899             }
   899             }
   900         return 0;
   900         return 0;
   901     }
   901     }
   916  */
   916  */
   917 static char *get_next_line(char ***lines, SDL_RWops *src, int len)
   917 static char *get_next_line(char ***lines, SDL_RWops *src, int len)
   918 {
   918 {
   919     char *linebufnew;
   919     char *linebufnew;
   920 
   920 
   921     if(lines) {
   921     if (lines) {
   922         return *(*lines)++;
   922         return *(*lines)++;
   923     } else {
   923     } else {
   924         char c;
   924         char c;
   925         int n;
   925         int n;
   926         do {
   926         do {
   927             if(SDL_RWread(src, &c, 1, 1) <= 0) {
   927             if (SDL_RWread(src, &c, 1, 1) <= 0) {
   928                 error = "Premature end of data";
   928                 error = "Premature end of data";
   929                 return NULL;
   929                 return NULL;
   930             }
   930             }
   931         } while(c != '"');
   931         } while (c != '"');
   932         if(len) {
   932         if (len) {
   933             len += 4;   /* "\",\n\0" */
   933             len += 4;   /* "\",\n\0" */
   934             if(len > buflen){
   934             if (len > buflen){
   935                 buflen = len;
   935                 buflen = len;
   936                 linebufnew = (char *)SDL_realloc(linebuf, buflen);
   936                 linebufnew = (char *)SDL_realloc(linebuf, buflen);
   937                 if(!linebufnew) {
   937                 if (!linebufnew) {
   938                     SDL_free(linebuf);
   938                     SDL_free(linebuf);
   939                     error = "Out of memory";
   939                     error = "Out of memory";
   940                     return NULL;
   940                     return NULL;
   941                 }
   941                 }
   942                 linebuf = linebufnew;
   942                 linebuf = linebufnew;
   943             }
   943             }
   944             if(SDL_RWread(src, linebuf, len - 1, 1) <= 0) {
   944             if (SDL_RWread(src, linebuf, len - 1, 1) <= 0) {
   945                 error = "Premature end of data";
   945                 error = "Premature end of data";
   946                 return NULL;
   946                 return NULL;
   947             }
   947             }
   948             n = len - 2;
   948             n = len - 2;
   949         } else {
   949         } else {
   950             n = 0;
   950             n = 0;
   951             do {
   951             do {
   952                 if(n >= buflen - 1) {
   952                 if (n >= buflen - 1) {
   953                     if(buflen == 0)
   953                     if (buflen == 0)
   954                         buflen = 16;
   954                         buflen = 16;
   955                     buflen *= 2;
   955                     buflen *= 2;
   956                     linebufnew = (char *)SDL_realloc(linebuf, buflen);
   956                     linebufnew = (char *)SDL_realloc(linebuf, buflen);
   957                     if(!linebufnew) {
   957                     if (!linebufnew) {
   958                         SDL_free(linebuf);
   958                         SDL_free(linebuf);
   959                         error = "Out of memory";
   959                         error = "Out of memory";
   960                         return NULL;
   960                         return NULL;
   961                     }
   961                     }
   962                     linebuf = linebufnew;
   962                     linebuf = linebufnew;
   963                 }
   963                 }
   964                 if(SDL_RWread(src, linebuf + n, 1, 1) <= 0) {
   964                 if (SDL_RWread(src, linebuf + n, 1, 1) <= 0) {
   965                     error = "Premature end of data";
   965                     error = "Premature end of data";
   966                     return NULL;
   966                     return NULL;
   967                 }
   967                 }
   968             } while(linebuf[n++] != '"');
   968             } while (linebuf[n++] != '"');
   969             n--;
   969             n--;
   970         }
   970         }
   971         linebuf[n] = '\0';
   971         linebuf[n] = '\0';
   972         return linebuf;
   972         return linebuf;
   973     }
   973     }
   974 }
   974 }
   975 
   975 
   976 #define SKIPSPACE(p)                \
   976 #define SKIPSPACE(p)                \
   977 do {                        \
   977 do {                        \
   978     while(SDL_isspace((unsigned char)*(p))) \
   978     while (SDL_isspace((unsigned char)*(p))) \
   979           ++(p);                \
   979           ++(p);                \
   980 } while(0)
   980 } while (0)
   981 
   981 
   982 #define SKIPNONSPACE(p)                 \
   982 #define SKIPNONSPACE(p)                 \
   983 do {                            \
   983 do {                            \
   984     while(!SDL_isspace((unsigned char)*(p)) && *p)  \
   984     while (!SDL_isspace((unsigned char)*(p)) && *p)  \
   985           ++(p);                    \
   985           ++(p);                    \
   986 } while(0)
   986 } while (0)
   987 
   987 
   988 /* read XPM from either array or RWops */
   988 /* read XPM from either array or RWops */
   989 static SDL_Surface *load_xpm(char **xpm, SDL_RWops *src)
   989 static SDL_Surface *load_xpm(char **xpm, SDL_RWops *src)
   990 {
   990 {
   991     Sint64 start = 0;
   991     Sint64 start = 0;
  1004 
  1004 
  1005     error = NULL;
  1005     error = NULL;
  1006     linebuf = NULL;
  1006     linebuf = NULL;
  1007     buflen = 0;
  1007     buflen = 0;
  1008 
  1008 
  1009     if ( src )
  1009     if (src)
  1010         start = SDL_RWtell(src);
  1010         start = SDL_RWtell(src);
  1011 
  1011 
  1012     if(xpm)
  1012     if (xpm)
  1013         xpmlines = &xpm;
  1013         xpmlines = &xpm;
  1014 
  1014 
  1015     line = get_next_line(xpmlines, src, 0);
  1015     line = get_next_line(xpmlines, src, 0);
  1016     if(!line)
  1016     if (!line)
  1017         goto done;
  1017         goto done;
  1018     /*
  1018     /*
  1019      * The header string of an XPMv3 image has the format
  1019      * The header string of an XPMv3 image has the format
  1020      *
  1020      *
  1021      * <width> <height> <ncolors> <cpp> [ <hotspot_x> <hotspot_y> ]
  1021      * <width> <height> <ncolors> <cpp> [ <hotspot_x> <hotspot_y> ]
  1022      *
  1022      *
  1023      * where the hotspot coords are intended for mouse cursors.
  1023      * where the hotspot coords are intended for mouse cursors.
  1024      * Right now we don't use the hotspots but it should be handled
  1024      * Right now we don't use the hotspots but it should be handled
  1025      * one day.
  1025      * one day.
  1026      */
  1026      */
  1027     if(SDL_sscanf(line, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4
  1027     if (SDL_sscanf(line, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4
  1028        || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) {
  1028        || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) {
  1029         error = "Invalid format description";
  1029         error = "Invalid format description";
  1030         goto done;
  1030         goto done;
  1031     }
  1031     }
  1032 
  1032 
  1033     keystrings = (char *)SDL_malloc(ncolors * cpp);
  1033     keystrings = (char *)SDL_malloc(ncolors * cpp);
  1034     if(!keystrings) {
  1034     if (!keystrings) {
  1035         error = "Out of memory";
  1035         error = "Out of memory";
  1036         goto done;
  1036         goto done;
  1037     }
  1037     }
  1038     nextkey = keystrings;
  1038     nextkey = keystrings;
  1039 
  1039 
  1040     /* Create the new surface */
  1040     /* Create the new surface */
  1041     if(ncolors <= 256) {
  1041     if (ncolors <= 256) {
  1042         indexed = 1;
  1042         indexed = 1;
  1043         image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8,
  1043         image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8,
  1044                          0, 0, 0, 0);
  1044                          0, 0, 0, 0);
  1045         im_colors = image->format->palette->colors;
  1045         im_colors = image->format->palette->colors;
  1046         image->format->palette->ncolors = ncolors;
  1046         image->format->palette->ncolors = ncolors;
  1047     } else {
  1047     } else {
  1048         indexed = 0;
  1048         indexed = 0;
  1049         image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
  1049         image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
  1050                          0xff0000, 0x00ff00, 0x0000ff, 0);
  1050                          0xff0000, 0x00ff00, 0x0000ff, 0);
  1051     }
  1051     }
  1052     if(!image) {
  1052     if (!image) {
  1053         /* Hmm, some SDL error (out of memory?) */
  1053         /* Hmm, some SDL error (out of memory?) */
  1054         goto done;
  1054         goto done;
  1055     }
  1055     }
  1056 
  1056 
  1057     /* Read the colors */
  1057     /* Read the colors */
  1058     colors = create_colorhash(ncolors);
  1058     colors = create_colorhash(ncolors);
  1059     if (!colors) {
  1059     if (!colors) {
  1060         error = "Out of memory";
  1060         error = "Out of memory";
  1061         goto done;
  1061         goto done;
  1062     }
  1062     }
  1063     for(index = 0; index < ncolors; ++index ) {
  1063     for (index = 0; index < ncolors; ++index ) {
  1064         char *p;
  1064         char *p;
  1065         line = get_next_line(xpmlines, src, 0);
  1065         line = get_next_line(xpmlines, src, 0);
  1066         if(!line)
  1066         if (!line)
  1067             goto done;
  1067             goto done;
  1068 
  1068 
  1069         p = line + cpp + 1;
  1069         p = line + cpp + 1;
  1070 
  1070 
  1071         /* parse a colour definition */
  1071         /* parse a colour definition */
  1072         for(;;) {
  1072         for (;;) {
  1073             char nametype;
  1073             char nametype;
  1074             char *colname;
  1074             char *colname;
  1075             Uint32 rgb, pixel;
  1075             Uint32 rgb, pixel;
  1076 
  1076 
  1077             SKIPSPACE(p);
  1077             SKIPSPACE(p);
  1078             if(!*p) {
  1078             if (!*p) {
  1079                 error = "colour parse error";
  1079                 error = "colour parse error";
  1080                 goto done;
  1080                 goto done;
  1081             }
  1081             }
  1082             nametype = *p;
  1082             nametype = *p;
  1083             SKIPNONSPACE(p);
  1083             SKIPNONSPACE(p);
  1084             SKIPSPACE(p);
  1084             SKIPSPACE(p);
  1085             colname = p;
  1085             colname = p;
  1086             SKIPNONSPACE(p);
  1086             SKIPNONSPACE(p);
  1087             if(nametype == 's')
  1087             if (nametype == 's')
  1088                 continue;      /* skip symbolic colour names */
  1088                 continue;      /* skip symbolic colour names */
  1089 
  1089 
  1090             if(!color_to_rgb(colname, p - colname, &rgb))
  1090             if (!color_to_rgb(colname, p - colname, &rgb))
  1091                 continue;
  1091                 continue;
  1092 
  1092 
  1093             SDL_memcpy(nextkey, line, cpp);
  1093             SDL_memcpy(nextkey, line, cpp);
  1094             if(indexed) {
  1094             if (indexed) {
  1095                 SDL_Color *c = im_colors + index;
  1095                 SDL_Color *c = im_colors + index;
  1096                 c->r = (Uint8)(rgb >> 16);
  1096                 c->r = (Uint8)(rgb >> 16);
  1097                 c->g = (Uint8)(rgb >> 8);
  1097                 c->g = (Uint8)(rgb >> 8);
  1098                 c->b = (Uint8)(rgb);
  1098                 c->b = (Uint8)(rgb);
  1099                 pixel = index;
  1099                 pixel = index;
  1100             } else
  1100             } else
  1101                 pixel = rgb;
  1101                 pixel = rgb;
  1102             add_colorhash(colors, nextkey, cpp, pixel);
  1102             add_colorhash(colors, nextkey, cpp, pixel);
  1103             nextkey += cpp;
  1103             nextkey += cpp;
  1104             if(rgb == 0xffffffff)
  1104             if (rgb == 0xffffffff)
  1105                 SDL_SetColorKey(image, SDL_TRUE, pixel);
  1105                 SDL_SetColorKey(image, SDL_TRUE, pixel);
  1106             break;
  1106             break;
  1107         }
  1107         }
  1108     }
  1108     }
  1109 
  1109 
  1110     /* Read the pixels */
  1110     /* Read the pixels */
  1111     pixels_len = w * cpp;
  1111     pixels_len = w * cpp;
  1112     dst = (Uint8 *)image->pixels;
  1112     dst = (Uint8 *)image->pixels;
  1113     for(y = 0; y < h; y++) {
  1113     for (y = 0; y < h; y++) {
  1114         line = get_next_line(xpmlines, src, pixels_len);
  1114         line = get_next_line(xpmlines, src, pixels_len);
  1115         if(indexed) {
  1115         if (!line)
       
  1116             goto done;
       
  1117 
       
  1118         if (indexed) {
  1116             /* optimization for some common cases */
  1119             /* optimization for some common cases */
  1117             if(cpp == 1)
  1120             if (cpp == 1)
  1118                 for(x = 0; x < w; x++)
  1121                 for (x = 0; x < w; x++)
  1119                     dst[x] = (Uint8)QUICK_COLORHASH(colors,
  1122                     dst[x] = (Uint8)QUICK_COLORHASH(colors,
  1120                                  line + x);
  1123                                  line + x);
  1121             else
  1124             else
  1122                 for(x = 0; x < w; x++)
  1125                 for (x = 0; x < w; x++)
  1123                     dst[x] = (Uint8)get_colorhash(colors,
  1126                     dst[x] = (Uint8)get_colorhash(colors,
  1124                                    line + x * cpp,
  1127                                    line + x * cpp,
  1125                                    cpp);
  1128                                    cpp);
  1126         } else {
  1129         } else {
  1127             for (x = 0; x < w; x++)
  1130             for (x = 0; x < w; x++)
  1131         }
  1134         }
  1132         dst += image->pitch;
  1135         dst += image->pitch;
  1133     }
  1136     }
  1134 
  1137 
  1135 done:
  1138 done:
  1136     if(error) {
  1139     if (error) {
  1137         if ( src )
  1140         if ( src )
  1138             SDL_RWseek(src, start, RW_SEEK_SET);
  1141             SDL_RWseek(src, start, RW_SEEK_SET);
  1139         if ( image ) {
  1142         if ( image ) {
  1140             SDL_FreeSurface(image);
  1143             SDL_FreeSurface(image);
  1141             image = NULL;
  1144             image = NULL;