9

I have Afile made by the equivalent of cat a.gif b.7z > Afile.

How may I split Afile into the original a.gif and b.7z files?

0

2 Answers 2

28

You'll have to figure out where the gif ends and where the 7z starts.

If you don't know the original size of the gif file, you can try and spot the start of the 7z file which should start with the 7z characters.

If you're lucky:

grep -boa 7z Afile

(assuming the GNU implementation of grep or compatible for its non-standard -b (byte offset), -o (output matched portion only) -a (all files including non-text ones)) will return only one:

<offset>:7z

Line where <offset> will be the offset in the file where the 7z file starts.

Then, you can extract them with:

tail -c +<offset+1> Afile > b.7z
head -c <offset> Afile > a.gif

For instance, if grep returns 1234:7z, run tail -c +1235 Afile > b.7z and head -c 1234 > a.gif.

If grep returns more than one, one of them will be the start of the 7z file whilst the other ones will just be the gif or 7z files happening to contain the 0x37 0x7a (the values of the 7 and z character in the ASCII set) byte sequence.

To determine which is the right one, you can pipe the output of tail -c for each of them to file - which should return something like 7-zip archive data for the right one. Or even try to list its contents with bsdtar tf - for instance.

tail -c +<offset+1> Afile | file -
tail -c +<offset+1> Afile | bsdtar tf -

The binwalk utility can be used to automate that process, as it tries to find file format signatures inside files (typically used to extract information from firmware images):

$ binwalk Afile

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             GIF image data, version "89a", 584 x 137
8570          0x217A          7-zip archive data, version 0.4

Ideally, as noted by @Henrik in comments, you'd want to look inside the gif part metadata for the information as to where the end of the GIF data is. I checked ImageMagick's identify, GNU extract, perl's Image::Info and exiftool, common tools that report information out of images and neither of them reported that information unfortunately.

It's likely possible to do it by hand by studying the GIF image format specification, another approach could be to hook into image viewers or converters to see where they stop reading the file when trying to parse the file.

I find that giftopnm from the venerable netpbm software lets me do that. In zsh:

zmodload zsh/system
{
  giftopnm > /dev/null
  head -c $(( systell(0) )) < Afile > a.gif
  cat > b.7z
} < Afile

Works in my test as giftopnm leaves the position within stdin just after the end of the gif file after converting to pnm (which we discard here).

That assumes the gif didn't already have extra information after the end of the data, which looks like it's not uncommon. See for instance libreoffice's gallery/htmlexpo/bludown.gif which has 212 seemingly random bytes after the end of the useful data. That cut.gif in openjdk seems to have 949 extra bytes (almost 80% of the size of the file!), including some Sun Microsystems copyright notice (not cleaned by mat2)

5
  • And binwalk -e will even automatically save the detected sections to separate files.
    – jpa
    Aug 7 at 9:34
  • @jpa, in theory yes, though in my tests it didn't work when trying it on the concatenation of a gif and 7z files and I didn't have time to investigate why which is why I didn't mention it. Aug 7 at 9:58
  • "7z" is only 16 bits. I don't know whether "7z" are two bytes that are likely to occur by random in a gif file of significant size, giving a false positive for where the 7-zip file starts. If I had to do something like this I would probably start by reading the size of the image in the gif, and from that try to deduce how many bytes belong to the gif file (but I don't know any tools to do that). That the 7-zip file has to start with "7z" can then be used as a sanity check. Aug 7 at 10:30
  • @Henriksupportsthecommunity, locate -0 '*.gif' | xargs -r0 grep -hc 7z | sort -rn | uniq -c can give you an idea of how many occurrences of 7z may be found in gif files. On my system, I find that 5189 out of 5444 don't have any. Before answering I checked ImageMagick's identify and exiftool and neither of them reported that information (unsurprisingly as that's not something that's otherwise very useful). Aug 7 at 12:39
  • @Henriksupportsthecommunity see edit that shows it's not always possible to determine the size of the gif file. Aug 7 at 13:09
1

Stephane's answer is very complete, I'm not offering an alternative answer to splitting your Afile back into its original a.gif and b.7z files. What I'm writing here is a different approach to combining your original files into a single file, so it's far easier to recover the original files.

The thing that made recovering your original files so difficult is that your original files were not simple text files, but both held binary data, and each was a different binary format from the other. The cat utility program does not add any boundary markers to make it easy to separate the combined file back into its original files. It also doesn't remember the original files' ownership and permissions, which is useful even if it wasn't part of your question here. However, there are other programs that are useful for combining dissimilar files into a single file, and extracting the original files out of the single file.

The most frequently used utility programs for this are tar and zip / unzip. Example commands that would have combined and extracted your files are:

# combining z.gif and b.7z into Afile
tar cf Afile a.gif b.7z
zip Afile a.gif b.7z

# recovering (usually called extracting) the original files
tar xf Afile
unzip Afile

Note that zip will usually add the suffix .zip to the name of your combined file (called an "archive file"), so the command zip Afile a.gif b.7z will produce a file named Afile.zip. Also, the convention with tar is to give the combined file a name with the suffix .tar, although you don't have to. It just helps you see which files are "tar files". Both of these utilities have features to do other things, like compress the data in the archive file. Compression wouldn't have helped with your particular two files, (they're already in compressed formats), but it can be useful with other types of files.

So this is a suggestion to make your life easier the next time you want to combine two or more files into a single file. It's a very common task in the Unix/Linux world, and the archive utility programs like tar and zip / unzip are almost always a better choice than cat.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.