Open IMG files

Started by DMWarrior, Apr 21, 2020, 03:35 AM

Previous topic - Next topic

DMWarrior

This script will let you open and dump content inside IMG files.
[noae][noae]/**
 * @class DirectoryArchive
 *
 * @description
 * Represents one DIR file, generally it's "gta3.dir".
 */
class DirectoryArchive {
  /** Table of Contents (TOC) of this DIR file. */
  toc = {};

  /**
   * @constructor
   *
   * @param {string} path File path.
   */
  constructor(path) {
    // File handler (the actual file object).
    local handler = file(path, "rb");

    // Iterate through DIR file...
    for(local i = 0; i < handler.len(); i += 32) {
      // File offset, size and name.
      local offset = handler.readn('i');
      local size   = handler.readn('i');
      local name   = "";

      // This will change to "true" after a string terminator is found...
      local isNameWritten = false;

      // Iterate through file name characters...
      for(local j = 0; j < 24; j++) {
        local char = handler.readn('b');

        // Ignore string terminator:
        if(char != 0x0 && isNameWritten == false) {
          name += format("%c", char);
        }

        // When it's found, changing this value to "true" will skip the rest.
        // This is done to align the seek:
        else {
          isNameWritten = true;
        }
      }

      // Save data information to it's TOC:
      this.toc[name] <- {
        offset = offset,
        size   = size,
        name   = name
      };
    }

    // After everything is done, close the file:
    handler.close();
  }
}

/**
 * @class ImageArchive
 *
 * @description
 * Represents one IMG file, generally it's "gta3.img".
 */
class ImageArchive {
  /** File path. */
  path = null;

  /** Directory archive. */
  directoryArchive = null;

  /**
   * @constructor
   *
   * @param {string} path File path.
   * @param {DirectoryArchive} directoryArchive Directory archive.
   */
  constructor(path, directoryArchive) {
    this.path = path;
    this.directoryArchive = directoryArchive;
  }

  /**
   * Dump one file inside of image file.
   *
   * @param {string} name File name.
   *
   * @return {blob} The requested file data.
   */
  function dump(name) {
    // Get the contents (if exists into directory archive's TOC)...
    if(name in this.directoryArchive.toc) {
      local contents = this.directoryArchive.toc[name];

      // File offset, size and name.
      local offset = contents.offset * 2048;
      local size   = contents.size * 2048;
      local name   = contents.name;

      // File handler (the actual file object).
      local handler = file(this.path, "rb");
            handler.seek(offset);

      // Requested file data.
      local data = handler.readblob(size);

      // After everything is done, close the file and return file data:
      handler.close();
      return data;
    }
  }
}
[/noae][/noae]
Here's an example. This will dump one DFF file and save it on server folder:
[noae][noae]// "gta3.dir" and "gta3.img" (these files must be into server folder):
local gta3dir = DirectoryArchive("gta3.dir");
local gta3img = ImageArchive("gta3.img", gta3dir);

// Taking one DFF object as example, this will return a blob object containing
// all it's data from the "gta3.img":
local dff = gta3img.dump("doontoon03.dff");

// Now all you need to do is to create one file and write to it:
local dffSave = file("doontoon03.dff", "wb");
      dffSave.writeblob(dff);
      dffSave.close();
[/noae][/noae]
There aren't many uses for this, though. The idea was to look around the map and dump the objects you wanted as you go, but that wouldn't work. And it's not like you couldn't use a map editor or IMG tool already, but that's another option anyway.

You can use this to take a look on how to read and write files in Squirrel if you need, too.

PSL

This feature is very powerful, thank you very much for sharing, but I know the ID of the buildings in the game, but how to get their names so I can shoot the buildings directly and export the model.