Exemplo n.º 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);
        }
Exemplo n.º 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);
        }