unsigned scan(unsigned char *addr, size_t len, int psd_version, struct layer_info *li) { unsigned char *p = addr, *q; size_t i; int j, k; unsigned n = 0, ps_ptr_bytes = 2 << psd_version; struct dictentry *de; for(i = 0; i < len;) { if(KEYMATCH((char*)p+i, "8BIM")){ i += 4; // found possible layer signature // check next 4 bytes for a known blend mode for(de = bmdict; de->key; ++de) if(!memcmp(de->key, (char*)p+i, 4)){ // found a possible layer blendmode signature // try to guess number of channels for(j = 1; j < 64; ++j){ q = p + i - 4 - j*(ps_ptr_bytes + 2) - 2; if(peek2B(q) == j){ long t = peek4B(q-16), l = peek4B(q-12), b = peek4B(q-8), r = peek4B(q-4); // sanity check bounding box if(b >= t && r >= l){ // sanity check channel ids for(k = 0; k < j; ++k){ int chid = peek2B(q + 2 + k*(ps_ptr_bytes + 2)); if(chid < -2 || chid >= j) break; // smells bad, give up } if(k == j){ // channel ids were ok. could still be a valid guess... ++n; if(li){ li->filepos = q - p - 16; ++li; } else VERBOSE("scavenge @ %8td : key: %c%c%c%c could be %d channel layer: t = %ld, l = %ld, b = %ld, r = %ld\n", q - p - 16, de->key[0], de->key[1], de->key[2], de->key[3], j, t, l, b, r); break; } } } } break; } }else ++i; } return n; }
static void displayinfo(int level, unsigned char data[]){ static const char *kind[] = {"ALPHACOLORSELECTED", "ALPHACOLORMASKED", "SPOTCHANNEL"}; const char *indent = tabs(level); if(xml){ fprintf(xml, "%s<%s>\n", indent, kind[data[12]]); colorspace(level+1, peek2B(data), data+2); fprintf(xml, "\t%s<OPACITY>%d</OPACITY>\n", indent, peek2B(data+10)); // kind values seem to be: // 0 = alpha channel, colour indicates selected areas // 1 = alpha channel, colour indicates masked areas // 2 = spot colour channel //fprintf(xml, "\t%s<KIND>%d</KIND>\n", indent, data[12]); fprintf(xml, "%s</%s>\n", indent, kind[data[12]]); } }
void scan_merged(unsigned char *addr, size_t len, struct psd_header *h) { size_t i, j = 0; unsigned ps_ptr_bytes = 2 << h->version; h->lmistart = h->lmilen = 0; // first search for a valid image resource block (these precede layer/mask info) for(i = 0; i < len;) { j = is_resource(addr, len, i); if(j && j < len-4){ VERBOSE("scavenge: possible resource id=%d @ %lu\n", peek2B(addr+i+4), (unsigned long)i); i = j; // found an apparently valid resource; skip over it // is it followed by another resource? if(memcmp("8BIM", addr+j, 4)) break; // no - stop looking }else ++i; } if(!j) alwayswarn("Did not find any plausible image resources; probably cannot locate merged image data.\n"); for(i = j; i < len; ++i) { psd_bytes_t lmilen = h->version == 2 ? peek8B(addr+i) : peek4B(addr+i), layerlen = h->version == 2 ? peek8B(addr+i+ps_ptr_bytes) : peek4B(addr+i+ps_ptr_bytes); if(lmilen > 0 && (i+lmilen) < len && layerlen == 0) { // sanity check compression type int comptype = peek2Bu(addr + i + lmilen); if(comptype == 0 || comptype == 1) { h->lmistart = i+ps_ptr_bytes; h->lmilen = lmilen; VERBOSE("scavenge: possible empty LMI @ %lld\n", h->lmistart); UNQUIET( "May be able to recover merged image if you can provide correct values\n\ for --mergedrows, --mergedcols, --mergedchan, --depth and --mode.\n"); break; // take first one } }