Example #1
0
    public static Grf grf_callback_open(string fname, string mode, GrfOpenCallback callback)
    {
        byte[] buf = new byte[GRF_HEADER_FULL_LEN];
        uint   i;//, zero_fcount = GrfSupport.ToLittleEndian32(7), create_ver = GrfSupport.ToLittleEndian32(0x0200);
        Grf    grf;

        if (fname == null || mode == null)
        {
            throw new Exception("GE_BADARGS");
        }

        /* Allocate memory for grf */
        grf = new Grf();

        /* Copy the filename */
        grf.filename = fname;

        /* Open the file */
        var fStream = FileManager.Load(grf.filename) as Stream;

        if (fStream == null)
        {
            throw new Exception("GE_ERRNO");
        }

        using (var br = new System.IO.BinaryReader(fStream)) {
            grf.allowWrite = !mode.Contains("+") && mode.Contains("w");

            //***skipped write***/

            /* Read the header */
            buf = br.ReadBytes(GRF_HEADER_FULL_LEN);

            /* Check the header */
            string strA = Encoding.ASCII.GetString(buf);
            int    v    = string.Compare(strA, 0, GRF_HEADER, 0, GRF_HEADER_LEN);
            if (v != 0)
            {
                throw new Exception("GE_INVALID");
            }

            /* Continued header check...
             *
             * GRF files that allow encryption of the files inside the archive
             * have a hex header following "Master of Magic" (not including
             * the nul-terminator) that looks like:
             * 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E
             *
             * GRF files that do not allow it have a hex header that looks like:
             * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
             *
             * GRF files that do not allow it are generally found after a
             * "Ragnarok.exe /repak" command has been issued
             */
            if (buf[GRF_HEADER_LEN + 1] == 1)
            {
                grf.allowCrypt = 1;
                /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E */
                for (i = 0; i < 0xF; i++)
                {
                    if (buf[GRF_HEADER_LEN + i] != (int)i)
                    {
                        throw new Exception("GE_CORRUPTED");
                    }
                }
            }
            else if (buf[GRF_HEADER_LEN] == 0)
            {
                grf.allowCrypt = 0;
                /* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */
                for (i = 0; i < 0xF; i++)
                {
                    if (buf[GRF_HEADER_LEN + i] != 0)
                    {
                        new Exception("GE_CORRUPTED");
                    }
                }
            }
            else
            {
                throw new Exception("GE_CORRUPTED");
            }

            /* Okay, so we finally are sure that its a valid GRF/GPF file.
             * now its time to read info from it
             */

            /* Set the type of archive this is */
            grf.type = GRF_TYPE_GRF;

            /* Read the version */
            grf.version = GrfSupport.LittleEndian32(buf, GRF_HEADER_MID_LEN + 0xC);

            /* Read the number of files */
            grf.nfiles  = GrfSupport.LittleEndian32(buf, GRF_HEADER_MID_LEN + 8);
            grf.nfiles -= GrfSupport.LittleEndian32(buf, GRF_HEADER_MID_LEN + 4) + 7;

            /* Create the array of files */
            grf.files = new Hashtable(StringComparer.OrdinalIgnoreCase);

            /* Grab the filesize */
            grf.len = (uint)fStream.Length;

            /* Seek to the offset of the file tables */
            br.BaseStream.Seek(GrfSupport.LittleEndian32(buf, GRF_HEADER_MID_LEN) + GRF_HEADER_FULL_LEN, SeekOrigin.Begin);

            /* Run a different function to read the file information based on
             * the major version number
             */
            switch (grf.version & 0xFF00)
            {
            case 0x0200:
                i = GRF_readVer2_info(br, grf, callback);
                break;

            default:
                throw new Exception("UNSUP_GRF_VERSION");
            }

            if (i > 0)
            {
                return(null);
            }
        }

        return(grf);
    }
Example #2
0
    /*! \brief Private function to read GRF0x2xx headers
     *
     * Reads the information about files within the archive...
     * for archive versions 0x02xx
     *
     * \todo Find GRF versions other than just 0x200 (do any exist?)
     *
     * \param grf Pointer to the Grf struct to read to
     * \param error Pointer to a GrfErrorType struct/enum for error reporting
     * \param callback Function to call for each read file. It should return 0 if
     *		everything is fine, 1 if everything is fine (but further
     *		reading should stop), or -1 if there has been an error
     * \return 0 if everything went fine, 1 if something went wrong
     */
    static uint GRF_readVer2_info(System.IO.BinaryReader br, Grf grf, GrfOpenCallback callback)
    {
        uint i, offset, len, len2;

        byte[] buf, zbuf;

        /* Check grf */
        if (grf.version != 0x200)
        {
            throw new Exception("GE_NSUP");
        }

        /* Read the original and compressed sizes */
        buf = br.ReadBytes(8);

        /* Allocate memory and read the compressed file table */
        len  = GrfSupport.LittleEndian32(buf, 0);
        zbuf = br.ReadBytes((int)len);

        if (0 == (len2 = GrfSupport.LittleEndian32(buf, 4)))
        {
            return(0);
        }

        /* Allocate memory and uncompress the compressed file table */
        Array.Resize(ref buf, (int)len2);

        var stream = new InflaterInputStream(new MemoryStream(zbuf));

        stream.Read(buf, 0, buf.Length);

        stream.Close();

        /* Read information about each file */
        for (i = offset = 0; i < grf.nfiles; i++)
        {
            /* Grab the filename length */
            len = GrfSupport.getCStringLength(buf, offset) + 1;

            /* Make sure its not too large */
            if (len >= GrfTypes.GRF_NAMELEN)
            {
                throw new Exception("GE_CORRUPTED");
            }

            /* Grab filename */
            GrfFile file = new GrfFile();
            file.name = GrfSupport.getCString(buf, offset);

            offset += len;

            /* Grab the rest of the information */
            file.compressed_len         = GrfSupport.LittleEndian32(buf, (int)offset);
            file.compressed_len_aligned = GrfSupport.LittleEndian32(buf, (int)offset + 4);
            file.real_len = GrfSupport.LittleEndian32(buf, (int)offset + 8);
            file.flags    = buf[offset + 0xC];
            file.pos      = GrfSupport.LittleEndian32(buf, (int)(offset + 0xD)) + (uint)GRF_HEADER_FULL_LEN;
            file.hash     = GrfSupport.GRF_NameHash(file.name);

            file.name = NormalizePath(file.name);

            grf.files.Add(file.name, file);

            /* Advance to the next file */
            offset += 0x11;

            /* Run the callback, if we have one */
            if (callback != null)
            {
                callback.doCallback(file);

                if (!callback.hasReturned())
                {
                    throw new Exception("NO_RETURN");
                }

                if (callback.Response < 0)
                {
                    /* Callback function had an error, so we
                     * have an error
                     */
                    return(1);
                }
                else if (callback.Response > 0)
                {
                    /* Callback function found the file it needed,
                     * just exit now
                     */
                    return(0);
                }
            }
        }

        /* Calling functions will set success...
         * GRF_SETERR(error,GE_SUCCESS,GRF_readVer2_info);
         */

        return(0);
    }