Пример #1
0
        public void Close()
        {
            var rawbuff  = memstream.ToArray();
            var cmpbuff  = JCR6.CompDrivers[storage].Compress(rawbuff);
            var astorage = storage;

            // TODO: "BRUTE" support entry closure
            if (storage != "Store" && rawbuff.Length <= cmpbuff.Length)
            {
                cmpbuff = rawbuff; astorage = "Store";
            }
            var NEntry = new TJCREntry();

            NEntry.Entry                    = entry;
            NEntry.Size                     = rawbuff.Length;
            NEntry.CompressedSize           = cmpbuff.Length;
            NEntry.Offset                   = (int)parent.mystream.Position;
            NEntry.Author                   = author;
            NEntry.Notes                    = notes;
            NEntry.Storage                  = astorage;
            NEntry.datastring["__JCR6FOR"]  = "C#";
            parent.Entries[entry.ToUpper()] = NEntry;
            parent.mystream.WriteBytes(cmpbuff);
            parent.OpenEntries.Remove(this);
            stream.Close();
        }
Пример #2
0
        /// <summary>
        /// Creates an "alias" of a JCR6 entry. In JCR6 an "Alias" is just a second entry poiting to the same data as another entry. With advanced JCR6 usage, this can sometimes make your life a lot easier.
        /// </summary>
        /// <remarks>If the target already exists, JCR6 will just override the reference, but NOT the data, so that can lead to unaccesible data in your JCR6 file. Second, JCR6 is NOT able to tell which entry is the "orginal" and which is the "target". For JCR6 they are just two separate entries and it really doesn't care that all their pointer data is the same.
        /// </remarks>
        /// <param name="original">Original entry.</param>
        /// <param name="target">Target entry.</param>
        public void Alias(string original, string target)
        {
            if (!Entries.ContainsKey(original.ToUpper()))
            {
                JCR6.JERROR = $"Cannot alias {original}. Entry not found!"; return;
            }
            var OEntry = Entries[original.ToUpper()];
            var TEntry = new TJCREntry();

            TEntry.Entry    = target;
            TEntry.MainFile = MainFile;
            foreach (string k in OEntry.datastring.Keys)
            {
                TEntry.datastring[k] = OEntry.datastring[k];
            }
            foreach (string k in OEntry.dataint.Keys)
            {
                TEntry.dataint[k] = OEntry.dataint[k];
            }
            foreach (string k in OEntry.databool.Keys)
            {
                TEntry.databool[k] = OEntry.databool[k];
            }
        }
Пример #3
0
        public override TJCRDIR Dir(string file)
        {
            var         ret = new TJCRDIR();
            QuickStream bt  = null;

            try {
                bt = QuickStream.ReadFile(file);
                if (bt.ReadString(header.Length) != header)
                {
                    throw new Exception("AR archive with incorrect header");
                }
                while (!bt.EOF)
                {
                    var e = new TJCREntry();
                    e.Entry = bt.ReadNullTerminatedString(16).Trim(); if (qstr.Suffixed(e.Entry, "/"))
                    {
                        e.Entry = qstr.Left(e.Entry, e.Entry.Length - 1);
                    }
                    Chat($"File: \"{e.Entry}\"");
                    e.dataint["__TimeStamp"] = qstr.ToInt(bt.ReadNullTerminatedString(12)); Chat($"TimeStamp: {e.dataint["__TimeStamp"]}!");
                    Chat($"OwnerID:  {bt.ReadNullTerminatedString(6)}"); // OwnerID -- Not relevant or supported by JCR6 (yet)
                    Chat($"GroupID:  {bt.ReadNullTerminatedString(6)}"); // GroupID -- Not relevant or supported by JCR6 (yet)
                    Chat($"FileMode: {bt.ReadNullTerminatedString(8)}"); // Permisisons -- Not yet relevant, but might be added later!
                    e.Size           = qstr.ToInt(bt.ReadNullTerminatedString(10)); Chat($"Size: {e.Size}");
                    e.CompressedSize = e.Size;
                    e.Storage        = "Store";
                    e.MainFile       = file;
                    //if (bt.ReadString(2) != ending) throw new Exception("End of file record is not 600A");
                    var e1 = bt.ReadByte();
                    var e2 = bt.ReadByte();
                    if (e1 != 0x60)
                    {
                        throw new Exception($"0x60 expected, but got {e1.ToString("X2")}");
                    }
                    if (e2 != 0x0a)
                    {
                        throw new Exception($"0x0a expected, but got {e1.ToString("X2")}");
                    }
                    ret.Entries[e.Entry.ToUpper()] = e;
                    e.Offset     = (int)bt.Position;
                    bt.Position += e.Size;
                    byte b;
                    do
                    {
                        b = bt.ReadByte();
                    } while (b == 10);
                    bt.Position--;
                }
                return(ret);
            } catch (Exception NETERROR) {
#if DEBUG
                JCR6.JERROR = $"{NETERROR.Message}\n{NETERROR.StackTrace}";
#else
                JCR6.JERROR = NETERROR.Message;
#endif
                return(null);
            } finally {
                if (bt != null)
                {
                    bt.Close();
                }
            }
        }
Пример #4
0
        public override TJCRDIR Dir(string file)
        {
            var  ret = new TJCRDIR();
            bool isJ = false;

            if (!File.Exists(file))
            {
                Console.WriteLine(file + " not found!");
                return(null);
            }
            var bt = QuickStream.ReadFile(file);

            isJ = bt.Size > 10; // I don't believe a JCR6 file can even get close to that!
            isJ = isJ && bt.ReadString(checkheader.Length) == checkheader;
            if (!isJ)
            {
                JCR6.JERROR = file + " is not a JCR6 file!"; bt.Close(); return(null);
            }                                                                                   // This error should NEVER be possible, unless you are using JCR6 NOT the way it was intended to be used.
            ret.FAToffset = bt.ReadInt();
            if (ret.FAToffset <= 0)
            {
                JCR6.JERROR = "Invalid FAT offset. Maybe you are trying to read a JCR6 file that has never been properly finalized";
                bt.Close();
                return(null);
            }
            byte   TTag = 0;
            string Tag  = "";

            do
            {
                TTag = bt.ReadByte();
                if (TTag != 255)
                {
                    Tag = bt.ReadString();
                }
                switch (TTag)
                {
                case 1:
                    ret.CFGstr[Tag] = bt.ReadString();
                    break;

                case 2:
                    ret.CFGbool[Tag] = bt.ReadByte() == 1;
                    break;

                case 3:
                    ret.CFGint[Tag] = bt.ReadInt();
                    break;

                case 255:
                    break;

                default:
                    JCR6.JERROR = $"Invalid config tag ({TTag}) {file}";
                    bt.Close();
                    return(null);
                }
            } while (TTag != 255);
            if (ret.CFGbool.ContainsKey("_CaseSensitive") && ret.CFGbool["_CaseSensitive"])
            {
                JCR6.JERROR = "Case Sensitive dir support was already deprecated and removed from JCR6 before it went to the Go language. It's only obvious that support for this was never implemented in C# in the first place.";
                bt.Close();
                return(null);
            }
            bt.Position = ret.FAToffset;
            bool theend = false;

            ret.FATsize    = bt.ReadInt();
            ret.FATcsize   = bt.ReadInt();
            ret.FATstorage = bt.ReadString();
            //  ret.Entries = map[string]TJCR6Entry{ } // Was needed in Go, but not in C#, as unlike Go, C# DOES support field assign+define
            var fatcbytes = bt.ReadBytes(ret.FATcsize);

            bt.Close();
            //Console.WriteLine(ret);
            if (!JCR6.CompDrivers.ContainsKey(ret.FATstorage))
            {
                JCR6.JERROR = "The File Table of file '" + file + "' was packed with the '" + ret.FATstorage + "' algorithm, but unfortunately I don't have drivers loaded for that one.";
                return(null);
            }
            var fatbytes = JCR6.CompDrivers[ret.FATstorage].Expand(fatcbytes, ret.FATsize);

            bt = QuickStream.StreamFromBytes(fatbytes, QuickStream.LittleEndian); // Little Endian is the default, but I need to make sure as JCR6 REQUIRES Little Endian for its directory structures.
            while ((!bt.EOF) && (!theend))
            {
                var mtag = bt.ReadByte();
                var ppp  = bt.Position;
                switch (mtag)
                {
                case 0xff:
                    theend = true;
                    break;

                case 0x01:
                    var tag = bt.ReadString().ToUpper();     //strings.ToUpper(qff.ReadString(btf));
                    switch (tag)
                    {
                    case "FILE":
                        var newentry = new TJCREntry();
                        newentry.MainFile = file;

                        /* Not needed in C#
                         * newentry.Datastring = map[string]string{}
                         * newentry.Dataint = map[string]int{}
                         * newentry.Databool = map[string]bool{}
                         */
                        var ftag = bt.ReadByte();
                        while (ftag != 255)
                        {
                            //chats("FILE TAG %d", ftag)
                            switch (ftag)
                            {
                            case 1:
                                var k = bt.ReadString();
                                var v = bt.ReadString();
                                newentry.datastring[k] = v;
                                break;

                            case 2:
                                var kb = bt.ReadString();
                                var vb = bt.ReadBoolean();
                                newentry.databool[kb] = vb;
                                break;

                            case 3:
                                var ki = bt.ReadString();
                                var vi = bt.ReadInt();
                                newentry.dataint[ki] = vi;
                                break;

                            case 255:
                                break;

                            default:
                                // p,_:= btf.Seek(0, 1)
                                JCR6.JERROR = $"Illegal tag in FILE part {ftag} on fatpos {bt.Position}";
                                bt.Close();
                                return(null);
                            }
                            ftag = bt.ReadByte();
                        }
                        var centry = newentry.Entry.ToUpper();
                        ret.Entries[centry] = newentry;
                        break;

                    case "COMMENT":
                        var commentname = bt.ReadString();
                        ret.Comments[commentname] = bt.ReadString();
                        break;

                    case "IMPORT":
                    case "REQUIRE":
                        //if impdebug {
                        //    fmt.Printf("%s request from %s\n", tag, file)
                        //                    }
                        // Now we're playing with power. Tha ability of
                        // JCR6 to automatically patch other files into
                        // one resource
                        var    deptag = bt.ReadByte();
                        string depk;
                        string depv;
                        var    depm = new Dictionary <string, string>();
                        while (deptag != 255)
                        {
                            depk       = bt.ReadString();
                            depv       = bt.ReadString();
                            depm[depk] = depv;
                            deptag     = bt.ReadByte();
                        }
                        var depfile = depm["File"];
                        //depsig   := depm["Signature"]
                        var deppatha = depm.ContainsKey("AllowPath") && depm["AllowPath"] == "TRUE";
                        var depcall  = "";
                        // var depgetpaths[2][] string
                        List <string>[] depgetpaths = new List <string> [2];
                        depgetpaths[0] = new List <string>();
                        depgetpaths[1] = new List <string>();
                        var owndir  = Path.GetDirectoryName(file);
                        int deppath = 0;

                        /*if impdebug{
                         *  fmt.Printf("= Wanted file: %s\n",depfile)
                         *     fmt.Printf("= Allow Path:  %d\n",deppatha)
                         *     fmt.Printf("= ValConv:     %d\n",deppath)
                         *     fmt.Printf("= Prio entnum  %d\n",len(ret.Entries))
                         * }*/
                        if (deppatha)
                        {
                            deppath = 1;
                        }
                        if (owndir != "")
                        {
                            owndir += "/";
                        }
                        depgetpaths[0].Add(owndir);
                        depgetpaths[1].Add(owndir);
                        // TODO: JCR6: depgetpaths[1] = append(depgetpaths[1], dirry.Dirry("$AppData$/JCR6/Dependencies/") )
                        if (qstr.Left(depfile, 1) != "/" && qstr.Left(depfile, 2) != ":")
                        {
                            foreach (string depdir in depgetpaths[deppath])         //for _,depdir:=range depgetpaths[deppath]
                            {
                                if ((depcall == "") && File.Exists(depdir + depfile))
                                {
                                    depcall = depdir + depfile;
                                }         /*else if (depcall=="" && impdebug ){
                                           * if !qff.Exists(depdir+depfile) {
                                           *    fmt.Printf("It seems %s doesn't exist!!\n",depdir+depfile)
                                           * }*/
                            }
                        }
                        else
                        {
                            if (File.Exists(depfile))
                            {
                                depcall = depfile;
                            }
                        }
                        if (depcall != "")
                        {
                            ret.PatchFile(depcall);
                            if (JCR6.JERROR != "" && tag == "REQUIRE")
                            {                                                                                                                     //((!ret.PatchFile(depcall)) && tag=="REQUIRE"){
                                JCR6.JERROR = "Required JCR6 addon file (" + depcall + ") could not imported! Importer reported: " + JCR6.JERROR; //,fil,"N/A","JCR 6 Driver: Dir()")
                                bt.Close();
                                return(null);
                            }
                            else if (tag == "REQUIRE")
                            {
                                JCR6.JERROR = "Required JCR6 addon file (" + depcall + ") could not found!";         //,fil,"N/A","JCR 6 Driver: Dir()")
                                bt.Close();
                                return(null);
                            }
                        }         /*else if impdebug {
                                   * fmt.Printf("Importing %s failed!", depfile);
                                   * fmt.Printf("Request:    %s", tag);
                                   * }*/
                        break;
                    }
                    break;

                default:
                    JCR6.JERROR  = $"Unknown main tag {mtag}, at file table position ";
                    JCR6.JERROR += bt.Position;
                    bt.Close();
                    return(null);
                }
            }
            bt.Close();
            return(ret); // Actual reader comes later.
        }
Пример #5
0
        override public TJCRDIR Dir(string file)
        {
            var Ret    = new TJCRDIR();
            var BT     = QuickStream.ReadFile(file, QuickStream.LittleEndian);
            var Header = "";
            var FE     = new TJCREntry();
            int Tag;
            int Length;

            byte[] PackedBank;
            byte[] UnpackedBank;
            long   PackedSize;
            long   UnPackedSize;
            //Local JCRD_DumpError$= ""
            var JCRFILE = file;

            if (BT == null)
            {
                JCR_JAMERR("JCR_Dir(~q" + JCRFILE + "~q): JCR file has not been found!", file, "N/A", "Dir");
                return(null);
            }
            Header = BT.ReadString(5);
            if (Header != "JCR5" + qstr.Chr(26))
            {
                JCR_JAMERR("JCR_Dir(~q" + JCRFILE + "~q): File given appears not to be a JCR 5 file!", file, "N/A", "Dir");
                BT.Close();
                return(null);
            }
            var FatOffSet = BT.ReadLong();

            if (FatOffSet > BT.Size)
            {
                JCR_JAMERR("JCR_Dir(~q" + JCRFILE + "~q): FAT offset beyond EOF (" + FatOffSet + ">" + BT.Size, file, "N/A", "Dir");
                BT.Close();
                return(null);
            }
            BT.Position = FatOffSet;
            do
            {//Repeat
                Tag = BT.ReadByte();
                //'DebugLog "JCR-TAG:"+Tag
                switch (Tag)
                {
                case 0xff: break;

                case 0: BT.ReadLong(); break;     //'JCRD_Print "JCR File ~q"+JCRFILE+"~q contains "+ReadLong(BT)+" entries~n~n"

                case 1: FE = new TJCREntry(); FE.MainFile = JCRFILE; break;

                case 2:
                    Length = BT.ReadInt();
                    //'DebugLog "FLen = "+Length;
                    FE.Entry = BT.ReadString(Length);
                    Ret.Entries[FE.Entry.ToUpper()] = FE;     //MapInsert Ret.Entries, Upper(FE.FileName), FE;
                                                              //'DebugLog "Found: "+FE.FIleName
                    break;

                case 3: FE.Size = (int)BT.ReadLong(); break;

                case 4: FE.Offset = (int)BT.ReadLong(); break;

                case 5: BT.ReadInt(); break;     //' FE.Time = ReadInt(BT) ' Not supported in JCR6 yet(strictly speaking it's easy to support it, but it's not needed in JCR6's purpose and therefore not supported by this driver)

                case 6: BT.ReadInt(); break;     //'FE.Permissions = ReadInt(BT) ' Permissions not supported in JCR6 yet, and I doubt they ever will be.

                case 7: FE.Storage = StorageName[BT.ReadInt()]; break;

                case 8: BT.ReadInt(); break;     //' FE.Encryption = ReadInt(BT) ' This was never worked out in JCR5, no need to consider any support for it in JCR6

                case 9: FE.CompressedSize = (int)BT.ReadLong(); break;

                case 10:
                    Length = BT.ReadInt();
                    //'DebugLog "ALen = "+Length;
                    FE.Author = BT.ReadString(Length);
                    break;

                case 11:
                    Length   = BT.ReadInt();
                    FE.Notes = BT.ReadString(Length);
                    break;

                case 12:
                    BT.ReadByte();
                    //'FE.Comment = ReadByte(BT)
                    //'If FE.Comment And (Not LoadComments) MapRemove Ret,Upper(FE.FileName)
                    break;

                case 200: XTag(BT, Ret, false, JCRFILE); break;

                case 254:
                    //'JCRD_Print "This JCR file contains a compressed FAT"
                    UnPackedSize = BT.ReadLong();
                    PackedSize   = BT.ReadLong();
                    //Unpackedbank = new byte[UnPackedSize]; //CreateBank(UnpackedSize)
                    //PackedBank = new byte[PackedSize]; //= CreateBank(PackedSize)
                    PackedBank = BT.ReadBytes((int)PackedSize);
                    //ReadBank PackedBank, BT, 0, PackedSize
                    //uncompress BankBuf(UnPackedBank), UnpackedSize, BankBuf(PackedBank), PackedSize
                    BT.Close();
                    if (!JCR6.CompDrivers.ContainsKey("zlib"))
                    {
                        JCR6.JERROR = "The file table of this JCR6 file has been packed with the zlib algorithm!";
                        return(null);
                    }
                    UnpackedBank = JCR6.CompDrivers["zlib"].Expand(PackedBank, (int)UnPackedSize);
                    BT           = new QuickStream(new System.IO.MemoryStream(UnpackedBank)); //CreateBankStream(UnPackedBank); BT = LittleEndianStream(BT)
                    break;

                default:
                    JCR_JAMERR("JCR_Dir(~q" + JCRFILE + "~q): Unknown FAT Tag (" + Tag + ")", file, "N/A", "Dir");
                    BT.Close();
                    return(null);
                }
            } while (Tag != 0xff);
            //Forever
            BT.Close();
            return(Ret);
        }
Пример #6
0
        override public TJCRDIR Dir(string file)
        {
            var QuakePAK = file;
            //var SupportLevel = false;
            var       Returner = new TJCRDIR();
            TJCREntry E;
            var       BT = QuickStream.ReadFile(QuakePAK, QuickStream.LittleEndian);

            //var Level = "";
            //Local LevelFiles$[] = ["THINGS","LINEDEFS","SIDEDEFS","VERTEXES","SEGS","SSECTORS","NODES","SECTORS","REJECT","BLOCKMAP","BEHAVIOR"] ' All files used in a DOOM/HERETIC/HEXEN level, in which I must note that "BEHAVIOR" is only used in HEXEN.
            if (BT == null)
            {
                //'JCRD_DumpError = "JCR_FetchQuakePAK(~q"+QuakePAK+"~q): QuakePAK file could not be read"
                JCR6.JERROR = "QuakePAK file could not be read!\n\n" + QuakePAK;
                BT.Close();
                return(null);
            }
            var Header = BT.ReadString(4);

            switch (Header)
            {
            case "PACK":
                break;     //Print "Quake Pack?"

            default:
                JCR6.JERROR = "JCR_Fetch(\"" + QuakePAK + "\"): Requested file is not a QuakePAK file";
                BT.Close();
                return(null);
            }
            Returner.CFGbool["__CaseSensitive"] = false;
            //'Next in the QuakePAK files are 2 32bit int values telling how many files the QuakePAK file contains and where in the QuakePAK file the File Table is stored
            var    DirOffset = BT.ReadInt();
            var    FileCount = BT.ReadInt();
            string FN;

            string[] FNS;
            //DebugLog "This QuakePAK contains "+(FileCount/64)+" entries starting at "+DirOffset
            BT.Position = DirOffset;
            //And let's now read all the crap
            for (int Ak = 0; Ak < FileCount; Ak += 64)
            {
                //'DebugLog "Reading entry #"+Ak
                if (BT.EOF)
                {
                    break;
                }
                E = new TJCREntry();
                //E.PVars = New StringMap ' Just has to be present to prevent crashes in viewer based software.
                E.MainFile       = QuakePAK;
                FN               = BT.ReadString(56);
                E.Offset         = BT.ReadInt();
                E.Size           = BT.ReadInt();
                FNS              = FN.Split((char)0);
                E.Entry          = FNS[0];  //'Replace(Trim(ReadString(BT,8)),Chr(0),"")
                E.CompressedSize = E.Size;
                E.Storage        = "Store"; // QuakePAK does not support compression, so always deal this as "Stored"
                //'E.Encryption = 0  ' QuakePAK does not support encryption, so always value 0
                //'If SupportLevel ' If set the system will turn DOOM levels into a folder for better usage. When unset the system will just dump everything together with not the best results, but hey, who cares :)
                //'Print "File = "+E.FileName+" >> Level = ~q"+Level+"~q >> Len="+Len(E.FileName)+" >> 1 = "+Left(E.FileName,1)+" >> 3 = "+Mid(E.FileName,3,1)
                //'If Level=""
                //Rem
                //If(Left(E.FileName, 3) = "MAP")
                //Level = "MAP_" + E.FileName + "/"
                //ElseIf((Len(E.FileName) = 4 And Left(E.FileName, 1) = "E" And Mid(E.FileName, 3, 1) = "M"))
                //Level = "MAP_" + E.FileName + "/"
                //ElseIf Level<>""
                //End Rem
                //var Ok = false;
                //            For Local S$= EachIn LevelFiles
                // If E.FileName = S Ok = True
                //
                //'Print "Comparing "+E.FileName+" with "+S+"   >>>> "+Ok
                //
                //Next
                //'If Ok E.FileName = Level+E.FileName Else level=""
                //'EndIf
                //'EndIf
                //Print "Adding: " + E.FileName
                Returner.Entries[E.Entry.ToUpper()] = E;
            }
            BT.Close();
            //'Return Ret
            return(Returner);
        }
Пример #7
0
        private TJCRDIR RDir(string file, bool ap)
        {
            /*
             * // init
             * var ret = new TJCRDIR();
             * var path = file;
             * var w = new List<string>();
             * var di = new DirectoryInfo(path);
             * ret.Comments["Real Dir"] = "Actually \"" + path + "\" is not a JCR6 resource, but a directory \"faked\" into a JCR6 resource.";
             * // Check
             * if (!di.Exists) {
             *  FLError = "UseJCR6.JCR6_RealDir.Dir(\"" + path + "\"): Directory does not exist!";
             *  return null;
             * }
             * // Listout
             * foreach (DirectoryInfo fi in di.GetDirectories()) {
             *  if (allowhidden || fi.Name.Substring(0, 1) != ".") {
             *      JCR6.dCHAT("Recursing: " + fi.Name);
             *      var a = JCR6.Dir(path + "/" + fi.Name);
             *      foreach (string k in a.Entries.Keys) {
             *          var ke = a.Entries[k];
             *          ret.Entries[(fi.Name + "/" + k).ToUpper()] = ke;
             *          ke.Entry = fi.Name + "/" + ke.Entry;
             *          ke.MainFile = qstr.ExtractDir(path) + "/" + fi.Name + "/" + ke.Entry;
             *      }
             *  }
             * }
             * foreach (FileInfo fi in di.GetFiles()) {
             *  if (automerge && JCR6.Recognize(path + "/" + fi.Name) != "NONE") {
             *      var a = JCR6.Dir(path + "/" + fi.Name);
             *      if (a == null) {
             *          Console.WriteLine($"WARNING! Scanning {fi.Name} failed >> {JCR6.JERROR}");
             *      } else {
             *          foreach (string k in a.Entries.Keys) {
             *              var ke = a.Entries[k];
             *              ret.Entries[(fi.Name + "/" + k).ToUpper()] = ke;
             *              ke.Entry = fi.Name + "/" + ke.Entry;
             *              ke.MainFile = path + "/" + ke.Entry;
             *          }
             *          foreach (string k in a.Comments.Keys) { ret.Comments[k] = a.Comments[k]; }
             *      }
             *  } else {
             *      var e = new TJCREntry();
             *      e.Entry = fi.Name;
             *      e.MainFile = path + "/" + fi.Name;
             *      e.Storage = "Store";
             *      e.CompressedSize = (int)fi.Length;
             *      e.Size = (int)fi.Length;
             *      ret.Entries[fi.Name.ToUpper()] = e;
             *  }
             * }
             */
            var ret = new TJCRDIR();
            var dir = FileList.GetTree(file, true, allowhidden);

            ret.Comments["Real Dir"] = "Actually \"" + file + "\" is not a JCR6 resource, but a directory \"faked\" into a JCR6 resource.";
            foreach (string chkfile in dir)
            {
                var mf = $"{file.Replace('\\', '/')}/{chkfile}";
                if (automerge && JCR6.Recognize(mf) != "NONE")
                {
                    var t = JCR6.Dir(mf);
                    if (t == null)
                    {
                        Debug.WriteLine($"Error in auto-merge JCR: {JCR6.JERROR}");
                    }
                    else
                    {
                        foreach (string k in t.Entries.Keys)
                        {
                            var ke = t.Entries[k];
                            ret.Entries[$"{chkfile.ToUpper()}/{k}"] = ke;
                            ke.Entry    = chkfile + "/" + ke.Entry;
                            ke.MainFile = mf; //+ "/" + ke.Entry;
                        }
                    }
                }
                else
                {
                    var e  = new TJCREntry();
                    var fi = new FileInfo(mf);
                    e.Entry          = chkfile; //fi.Name;
                    e.MainFile       = mf;
                    e.Storage        = "Store";
                    e.CompressedSize = (int)fi.Length;
                    e.Size           = (int)fi.Length;
                    e.Offset         = 0;
                    ret.Entries[chkfile.ToUpper()] = e;
                }
            }
            // return the crap
            return(ret);
        }
Пример #8
0
        public override TJCRDIR Dir(string file)
        {
            //Private
            //Function JCR_FetchWAD:TJCRDir(WAD$, SupportLevel= 1)
            var Returner = new TJCRDIR();
            //var Ret:TMap = New TMap; returner.entries = ret
            TJCREntry E;
            var       BT    = QuickStream.ReadFile(file, QuickStream.LittleEndian);
            var       Level = "";

            string[] LevelFiles = { "THINGS", "LINEDEFS", "SIDEDEFS", "VERTEXES", "SEGS", "SSECTORS", "NODES", "SECTORS", "REJECT", "BLOCKMAP", "BEHAVIOR" }; //' All files used in a DOOM/HERETIC/HEXEN level, in which I must note that "BEHAVIOR" is only used in HEXEN.
            if (BT == null)
            {
                JCR6.JERROR = "WAD file could not be read!\n" + file;
                return(null);
            }
            //BT = LittleEndianStream(BT) ' WADs were all written for the MS-DOS platform, which used LittleEndian, so we must make sure that (even if the routine is used on PowerPC Macs) that LittleEndian is used
            //WAD files start with a header that can either be 'IWAD' for main wad files or 'PWAD' for patch WAD files. For JCR this makes no difference it all (it didn't even to WAD for that matter), but this is our only way to check if the WAD loaded is actually a WAD file.
            var Header = BT.ReadString(4);

            switch (Header)
            {
            case "IWAD":
                Returner.Comments["Important notice"] = "The WAD file you are viewing is an IWAD,\nmeaning it belongs to a copyrighted project.\n\nAll content within it is very likely protected by copyright\neither by iD software or Apogee's Developers of Incredible Power or Raven Software.\n\nNothing can stop you from analysing this file and viewing its contents,\nbut don't extract and distribute any contents of this file\nwithout proper permission from the original copyright holder";
                break;

            case "PWAD":
                Returner.Comments["Notice"] = "This WAD file is a PWAD or Patch-WAD. It's not part of any official file of the games using the WAD system. Please respect the original copyright holders copyrights though!";
                break;

            default:
                JCR6.JERROR = "JCR_FetchWAD('" + file + "'): Requested file is not a WAD file";
                return(null);
            }
            Returner.CFGbool["__CaseSensitive"] = false;
            //'Next in the WAD files are 2 32bit int values telling how many files the WAD file contains and where in the WAD file the File Table is stored
            var FileCount = BT.ReadInt();
            var DirOffset = BT.ReadInt();

            //DebugLog "This WAD contains "+FileCount+" entries starting at "+DirOffset
            BT.Position = DirOffset;
            // And let's now read all the crap
            for (int Ak = 1; Ak <= FileCount; Ak++)
            {
                //    'DebugLog "Reading entry #"+Ak
                E = new TJCREntry();
                // E.PVars = New StringMap ' Just has to be present to prevent crashes in viewer based software. // Not an issue in the C# version.
                E.MainFile       = file;
                E.Offset         = BT.ReadInt();
                E.Size           = BT.ReadInt();
                E.Entry          = BT.ReadString(8).Trim().Replace("\0", ""); //Replace(Trim(ReadString(BT, 8)), Chr(0), "")
                E.CompressedSize = E.Size;
                E.Storage        = "Store";                                   // WAD does not support compression, so always deal this as "Stored"
                //    'E.Encryption = 0  ' WAD does not support encryption, so always value 0
                if (SupportLevel)                                             // ' If set the system will turn DOOM levels into a folder for better usage. When unset the system will just dump everything together with not the best results, but hey, who cares :)
                {
                    //'Print "File = "+E.FileName+" >> Level = ~q"+Level+"~q >> Len="+Len(E.FileName)+" >> 1 = "+Left(E.FileName,1)+" >> 3 = "+Mid(E.FileName,3,1)
                    //'If Level=""
                    if (qstr.Left(E.Entry, 3) == "MAP")
                    {
                        Level = "MAP_" + E.Entry + "/";
                    }
                    else if (E.Entry.Length == 4 && qstr.Left(E.Entry, 1) == "E" && qstr.Mid(E.Entry, 3, 1) == "M")
                    {
                        Level = "MAP_" + E.Entry + "/";
                    }
                    else if (Level != "")
                    {
                        var Ok = false;
                        foreach (string S in LevelFiles)
                        {
                            Ok = Ok || E.Entry == S;
                            //'Print "Comparing "+E.FileName+" with "+S+"   >>>> "+Ok
                        }
                        if (Ok)
                        {
                            E.Entry = Level + E.Entry;
                        }
                        else
                        {
                            Level = "";
                        }
                    }
                }
                JCR6.dCHAT("Adding: " + E.Entry);
                Returner.Entries[E.Entry.ToUpper()] = E;
            }
            BT.Close();
            //Return Ret
            return(Returner);
        }
Пример #9
0
        public override TJCRDIR Dir(string file)
        {
            QuickStream BT = null;

            try {
                BT = QuickStream.ReadFile(file);
                var    ret = new TJCRDIR();
                string s;
                do
                {
                    if (BT.EOF)
                    {
                        throw new Exception("JQL heading not found!");
                    }
                    s = RL(BT);
                } while (s == "" || qstr.Prefixed(s, "#"));
                if (s != "JQL")
                {
                    throw new Exception("JQL not properly headed!");
                }
                var optional = true;
                var author   = "";
                var notes    = "";
                while (!BT.EOF)
                {
                    s = RL(BT);
                    var c = new QP(s);
                    if (s != "" && (!qstr.Prefixed(s, "#")))
                    {
                        switch (c.commando)
                        {
                        case "REQUIRED":
                        case "REQ":
                            optional = false;
                            break;

                        case "OPTIONAL":
                        case "OPT":
                            optional = true;
                            break;

                        case "PATCH": {
                            var to = c.parameter.IndexOf('>');
                            if (to < 0)
                            {
                                var p = JCR6.Dir(c.parameter);
                                if (p == null)
                                {
                                    if (optional)
                                    {
                                        break;
                                    }
                                    throw new Exception($"Patch error {JCR6.JERROR}");
                                }
                                ret.Patch(p);
                            }
                            else
                            {
                                var rw = c.parameter.Substring(0, to).Trim().Replace("\\", "/");
                                var tg = c.parameter.Substring(to + 1).Trim().Replace("\\", "/");
                                var p  = JCR6.Dir(rw);
                                if (p == null)
                                {
                                    if (optional)
                                    {
                                        break;
                                    }
                                    throw new Exception($"Patch error {JCR6.JERROR}");
                                }
                                ret.Patch(p, tg);
                            }
                            break;
                        }

                        case "AUTHOR":
                        case "AUT":
                            author = c.parameter;
                            break;

                        case "NOTES":
                        case "NTS":
                            notes = c.parameter;
                            break;

                        case "RAW": {
                            var p  = c.parameter.IndexOf('>');
                            var rw = c.parameter.Replace("\\", "/");
                            var tg = rw;
                            if (p >= 0)
                            {
                                rw = c.parameter.Substring(0, p).Trim().Replace("\\", "/");
                                tg = c.parameter.Substring(p + 1).Trim().Replace("\\", "/");
                            }
                            if (tg.Length > 1 && tg[1] == ':')
                            {
                                tg = tg.Substring(2);
                            }
                            while (tg[1] == '/')
                            {
                                tg = tg.Substring(1);
                            }
                            if (rw == "")
                            {
                                throw new Exception("RAW no original");
                            }
                            if (tg == "")
                            {
                                throw new Exception("RAW no target");
                            }
                            if (!File.Exists(rw))
                            {
                                if (optional)
                                {
                                    break;
                                }
                                throw new Exception($"Required raw file \"{rw}\" doesn't exist!");
                            }
                            var e = new TJCREntry();
                            e.Entry                   = tg;
                            e.MainFile                = rw;
                            e.Storage                 = "Store";
                            e.Offset                  = 0;
                            e.Size                    = (int)new FileInfo(rw).Length;
                            e.CompressedSize          = e.Size;
                            e.Notes                   = notes;
                            e.Author                  = author;
                            ret.Entries[tg.ToUpper()] = e;
                            break;
                        }

                        case "TEXT":
                        case "TXT": {
                            var tg = c.parameter.Trim().Replace("\\", "/");
                            if (tg.Length > 1 && tg[1] == ':')
                            {
                                tg = tg.Substring(2);
                            }
                            while (tg[1] == '/')
                            {
                                tg = tg.Substring(1);
                            }
                            if (tg == "")
                            {
                                throw new Exception("TEXT no target");
                            }
                            var e   = new TJCREntry();
                            var buf = new byte[5];
                            e.Entry    = tg;
                            e.MainFile = file;
                            e.Storage  = "Store";
                            e.Offset   = (int)BT.Position;
                            e.Notes    = notes;
                            e.Author   = author;
                            do
                            {
                                if (BT.EOF)
                                {
                                    throw new Exception("Unexpected end of file (TXT Block not ended)");
                                }
                                for (int i = 0; i < 4; i++)
                                {
                                    buf[i] = buf[i + 1];
                                }
                                buf[4] = BT.ReadByte();
                                //Console.WriteLine(Encoding.UTF8.GetString(buf, 0, buf.Length));
                            } while (Encoding.UTF8.GetString(buf, 0, buf.Length) != "@END@");
                            RL(BT);
                            e.Size                    = (int)(BT.Position - 7) - e.Offset;
                            e.CompressedSize          = e.Size;
                            ret.Entries[tg.ToUpper()] = e;
                            break;
                        }

                        case "COMMENT":
                        case "CMT": {
                            if (c.parameter == "")
                            {
                                throw new Exception("Comment without a name");
                            }
                            var cmt = new StringBuilder("");
                            var l   = "";
                            do
                            {
                                if (BT.EOF)
                                {
                                    throw new Exception("Unexpected end of file (COMMENT block not ended)");
                                }
                                l = RL(BT, false);
                                if (l.Trim() != "@END@")
                                {
                                    cmt.Append($"{l}\n");
                                }
                            } while (l.Trim() != "@END@");
                            ret.Comments[c.parameter] = cmt.ToString();
                            break;
                        }

                        case "IMPORT":
                            ret.PatchFile(c.parameter);
                            break;

                        case "END":
                            return(ret);

                        default: throw new Exception($"Unknown instruction! {c.commando}");
                        }
                    }
                }
                return(ret);
            } catch (Exception e) {
                JCR6.JERROR = $"JQL error: {e.Message}";
#if DEBUG
                Console.WriteLine(e.StackTrace);
#endif
                return(null);
            } finally {
                if (BT != null)
                {
                    BT.Close();
                }
            }
        }
Пример #10
0
        private TJCRDIR RDir(string file, bool ap)
        {
            // init
            var ret  = new TJCRDIR();
            var path = file;
            var w    = new List <string>();
            var di   = new DirectoryInfo(path);

            ret.Comments["Real Dir"] = "Actually \"" + path + "\" is not a JCR6 resource, but a directory \"faked\" into a JCR6 resource.";
            // Check
            if (!di.Exists)
            {
                FLError = "UseJCR6.JCR6_RealDir.Dir(\"" + path + "\"): Directory does not exist!";
                return(null);
            }
            // Listout
            foreach (DirectoryInfo fi in di.GetDirectories())
            {
                if (allowhidden || fi.Name.Substring(0, 1) != ".")
                {
                    JCR6.dCHAT("Recursing: " + fi.Name);
                    var a = JCR6.Dir(path + "/" + fi.Name);
                    foreach (string k in a.Entries.Keys)
                    {
                        var ke = a.Entries[k];
                        ret.Entries[(fi.Name + "/" + k).ToUpper()] = ke;
                        ke.Entry    = fi.Name + "/" + ke.Entry;
                        ke.MainFile = path + "/" + fi.Name + "/" + ke.Entry;
                    }
                }
            }
            foreach (FileInfo fi in di.GetFiles())
            {
                if (automerge && JCR6.Recognize(path + "/" + fi.Name) != "NONE")
                {
                    var a = JCR6.Dir(path + "/" + fi.Name);
                    if (a == null)
                    {
                        Console.WriteLine($"WARNING! Scanning {fi.Name} failed >> {JCR6.JERROR}");
                    }
                    else
                    {
                        foreach (string k in a.Entries.Keys)
                        {
                            var ke = a.Entries[k];
                            ret.Entries[(fi.Name + "/" + k).ToUpper()] = ke;
                            ke.Entry    = fi.Name + "/" + ke.Entry;
                            ke.MainFile = path + "/" + ke.Entry;
                        }
                        foreach (string k in a.Comments.Keys)
                        {
                            ret.Comments[k] = a.Comments[k];
                        }
                    }
                }
                else
                {
                    var e = new TJCREntry();
                    e.Entry          = fi.Name;
                    e.MainFile       = path + "/" + fi.Name;
                    e.Storage        = "Store";
                    e.CompressedSize = (int)fi.Length;
                    e.Size           = (int)fi.Length;
                    ret.Entries[fi.Name.ToUpper()] = e;
                }
            }



            // return the crap
            return(ret);
        }
Пример #11
0
        void Scan(string file)
        {
            // Does the file even exist?
            if (!File.Exists(file))
            {
                Error($"File not found: {file}"); return;
            }
            // Prepare
            var Entries = new List <WWEnt>();
            // Open
            var   BT         = QuickStream.ReadFile(file);
            WWEnt First      = null;
            uint  LastOffset = 0;

            // Read the actual data
            do
            {
                var Ent = new WWEnt();
                if (First == null)
                {
                    First = Ent;
                }
                // 4-byte file start position.
                Ent.offset = BT.ReadUnSignedInt();

                var Position = BT.Position;
                // Trap for version 2 and 3 PAK files.
                if (Ent.offset > BT.Size)
                {
                    Error("Entry offset beyond EOF.");
                    return;
                }
                if (Ent.offset == 0)
                {
                    break;
                }
                else
                {
                    // Trap for version 1 PAK files.
                    if ((Position - 1) == First.offset)
                    {
                        //Entries.Add(Ent); //FileCount = FileCount + 1
                        break;
                    }
                    else
                    {
                        if (Ent.offset < LastOffset)
                        {
                            Error("Offset conflict. This cannot be a WestWood PAK");
                            return;
                        }
                        LastOffset = Ent.offset;
                        // Read the file name until we hit a null.
                        byte Char = 0;
                        do
                        {
                            Char = BT.ReadByte();
                            if (Char != 0)
                            {
                                Ent.FileName.Append((char)Char);
                                if (Char < 30 || Char > 126)
                                {
                                    Error($"Character #{Char} is not likely used in a file name! "); return;
                                }
                            }
                        } while (Char > 0);
                        Entries.Add(Ent); //FileCount = FileCount + 1
                    }
                }
            } while (true);
            // Reading itself is done now!
            var ResSize = (uint)BT.Size;

            BT.Close();

            // Working with an array is easier from this point
            var EntArray = Entries.ToArray();

            // Calculating file sizes (it's really beyond me why Westwood saw fit NOT to include that essential data)
            for (uint FileNo = 0; FileNo < EntArray.Length; ++FileNo)
            {
                uint FileSize = 0;
                var  cEnt     = EntArray[FileNo];
                // Get the file size.
                if (FileNo == EntArray.Length - 1)
                {
                    FileSize = ResSize - cEnt.offset;
                }
                else
                {
                    FileSize = EntArray[FileNo + 1].offset - cEnt.offset;
                }
                cEnt.size = FileSize;
            }

            // No to convert all collected data to data JCR6 can understand
            var Dir = new TJCRDIR();

            foreach (var WE in EntArray)
            {
                var E = new TJCREntry();
                E.Entry = WE.FileName.ToString();
                E.Size  = (int)WE.size; if (E.Size < 0)
                {
                    Error("Invalid size data. This Westwood file may have gone beyond the limitations of JCR6"); return;
                }                                                                                                                                             // The error is given the fact that this is a DOS format not likely to happen, but technically possible, so we must be prepared.
                E.Offset = (int)WE.offset; if (E.Size < 0)
                {
                    Error("Invalid offset data. This Westwood file may have gone beyond the limitations of JCR6"); return;
                }                                                                                                                                                     // The error is given the fact that this is a DOS format not likely to happen, but technically possible, so we must be prepared.
                E.Author         = "(?) Westwood Studios Inc. (?)";
                E.Notes          = "Please be aware that this file came from a Westwood PAK file. Aside from copyright the file format is so primitive that I cannot guarantee things went right";
                E.MainFile       = file;
                E.Storage        = "Store"; // The only format PAK supports anyway, so that's easy.
                E.CompressedSize = E.Size;
                if (E.Entry != "")
                {
                    Dir.Entries[E.Entry.ToUpper()] = E;
                }
            }
            LastScanned    = file;
            LastScannedDir = Dir;
        }