update for HEAD-2003091401
[reactos.git] / tools / cabman / dfp.cxx
diff --git a/tools/cabman/dfp.cxx b/tools/cabman/dfp.cxx
new file mode 100755 (executable)
index 0000000..d9de8ec
--- /dev/null
@@ -0,0 +1,1179 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS cabinet manager
+ * FILE:        tools/cabman/dfp.cpp
+ * PURPOSE:     Directive file parser
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * NOTES:       The directive file format is similar to the
+ *              directive file format used by Microsoft's MAKECAB
+ * REVISIONS:
+ *   CSH 21/03-2001 Created
+ *   CSH 15/08-2003 Made it portable
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include "cabinet.h"
+#include "dfp.h"
+
+
+/* CDFParser */
+
+CDFParser::CDFParser()
+/*
+ * FUNCTION: Default constructor
+ */
+{
+    InfFileOnly     = false;
+    DontGenerateInf = false;
+
+    FileBuffer     = NULL;
+    FileLoaded     = false;
+    CurrentOffset  = 0;
+    CurrentLine    = 0;
+    CabinetCreated = false;
+    DiskCreated    = false;
+    FolderCreated  = false;
+    CabinetName    = NULL;
+    DiskLabel      = NULL;
+    MaxDiskSize    = NULL;
+
+    MaxDiskSizeAllSet      = false;
+    CabinetNameTemplateSet = false;
+    DiskLabelTemplateSet   = false;
+    InfFileNameSet         = false;
+
+    InfModeEnabled = false;
+    InfFileHandle = NULL;
+}
+
+CDFParser::~CDFParser()
+/*
+ * FUNCTION: Default destructor
+ */
+{
+    PCABINET_NAME CNPrev;
+    PCABINET_NAME CNNext;
+    PDISK_NUMBER DNPrev;
+    PDISK_NUMBER DNNext;
+
+    if (FileBuffer)
+        FreeMemory(FileBuffer);
+    CNNext = CabinetName;
+    while (CNNext != NULL) {
+        CNPrev = CNNext->Next;
+        FreeMemory(CNNext);
+        CNNext = CNPrev;
+    }
+    CNNext = DiskLabel;
+    while (CNNext != NULL) {
+        CNPrev = CNNext->Next;
+        FreeMemory(CNNext);
+        CNNext = CNPrev;
+    }
+    DNNext = MaxDiskSize;
+    while (DNNext != NULL) {
+        DNPrev = DNNext->Next;
+        FreeMemory(DNNext);
+        DNNext = DNPrev;
+    }
+
+    if (InfFileHandle != NULL) {
+        CloseFile(InfFileHandle);
+    }
+}
+
+void CDFParser::WriteInfLine(char* InfLine)
+{
+    char buf[MAX_PATH];
+    char eolbuf[2];
+    char* destpath;
+#if defined(WIN32)
+    unsigned long BytesWritten;
+#endif
+
+    if (DontGenerateInf) {
+        return;
+    }
+
+    if (InfFileHandle == NULL) {
+        if (!InfFileNameSet) {
+            /* FIXME: Use cabinet name with extension .inf */
+            return;
+        }
+
+        destpath = GetDestinationPath();
+        if (strlen(destpath) > 0) {
+            strcpy(buf, destpath);
+            strcat(buf, InfFileName);
+        } else {
+            strcpy(buf, InfFileName);
+        }
+
+        /* Create .inf file, overwrite if it already exists */
+#if defined(WIN32)
+        InfFileHandle = CreateFile(buf,     // Create this file
+            GENERIC_WRITE,                  // Open for writing
+            0,                              // No sharing
+            NULL,                           // No security
+            CREATE_ALWAYS,                  // Create or overwrite
+            FILE_ATTRIBUTE_NORMAL,          // Normal file 
+            NULL);                          // No attribute template
+        if (InfFileHandle == INVALID_HANDLE_VALUE) {
+            DPRINT(MID_TRACE, ("Error creating '%d'.\n", (unsigned int)GetLastError()));
+            return;
+        }
+#else /* !WIN32 */
+        InfFileHandle = fopen(buf, "wb"); 
+        if (InfFileHandle == NULL) {
+            DPRINT(MID_TRACE, ("Error creating '%d'.\n", (unsigned int)errno));
+            return;
+        }
+#endif
+    }
+
+#if defined(WIN32)
+    if (!WriteFile(InfFileHandle, InfLine, strlen(InfLine), &BytesWritten, NULL)) {
+        DPRINT(MID_TRACE, ("ERROR WRITING '%d'.\n", (unsigned int)GetLastError()));
+        return;
+    }
+#else
+    if (fwrite(InfLine, strlen(InfLine), 1, InfFileHandle) < 1)
+        return;
+#endif
+
+    eolbuf[0] = 0x0d;
+    eolbuf[1] = 0x0a;
+
+#if defined(WIN32)
+    if (!WriteFile(InfFileHandle, eolbuf, sizeof(eolbuf), &BytesWritten, NULL)) {
+        DPRINT(MID_TRACE, ("ERROR WRITING '%d'.\n", (unsigned int)GetLastError()));
+        return;
+    }
+#else
+    if (fwrite(eolbuf, 1, sizeof(eolbuf), InfFileHandle) < 1)
+        return;
+#endif
+}
+
+
+unsigned long CDFParser::Load(char* FileName)
+/*
+ * FUNCTION: Loads a directive file into memory
+ * ARGUMENTS:
+ *     FileName = Pointer to name of directive file
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    unsigned long BytesRead;
+    long FileSize;
+
+    if (FileLoaded)
+        return CAB_STATUS_SUCCESS;
+
+    /* Create cabinet file, overwrite if it already exists */
+#if defined(WIN32)
+    FileHandle = CreateFile(FileName, // Create this file
+        GENERIC_READ,                 // Open for reading
+        0,                            // No sharing
+        NULL,                         // No security
+        OPEN_EXISTING,                // Open the file
+        FILE_ATTRIBUTE_NORMAL,        // Normal file
+        NULL);                        // No attribute template
+    if (FileHandle == INVALID_HANDLE_VALUE)
+        return CAB_STATUS_CANNOT_OPEN;
+#else /* !WIN32 */
+    FileHandle = fopen(FileName, "rb"); 
+    if (FileHandle == NULL) {
+        return CAB_STATUS_CANNOT_OPEN;
+    }
+#endif
+
+    FileSize = GetSizeOfFile(FileHandle);
+    if (FileSize == (unsigned long)-1) {
+        CloseFile(FileHandle);
+        return CAB_STATUS_CANNOT_OPEN;
+    }
+
+    FileBufferSize = (unsigned long)FileSize;
+
+    FileBuffer = (char*)AllocateMemory(FileBufferSize);
+    if (!FileBuffer) {
+        CloseFile(FileHandle);
+        return CAB_STATUS_NOMEMORY;
+    }
+
+    if (!ReadFileData(FileHandle, FileBuffer, FileBufferSize, &BytesRead)) {
+        CloseFile(FileHandle);
+        FreeMemory(FileBuffer);
+        FileBuffer = NULL;
+        return CAB_STATUS_CANNOT_READ;
+    }
+
+    CloseFile(FileHandle);
+
+    FileLoaded = true;
+
+    DPRINT(MAX_TRACE, ("File (%d bytes)\n", FileBufferSize));
+
+    return CAB_STATUS_SUCCESS;
+}
+
+
+unsigned long CDFParser::Parse()
+/*
+ * FUNCTION: Parses a loaded directive file
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    bool Command;
+    unsigned long Status;
+
+    if (!FileLoaded)
+        return CAB_STATUS_NOFILE;
+
+    while (ReadLine()) {
+        Command = false;
+
+        if (InfModeEnabled) {
+            bool WriteLine = true;
+            while (CurrentToken != TokenEnd) {
+                switch (CurrentToken) {
+                    case TokenIdentifier:
+                        if (Command) {
+                            /* Command */
+                            Status = PerformCommand();
+                            if (Status == CAB_STATUS_FAILURE) {
+                                WriteLine = true;
+                            } else {
+                                if (!InfModeEnabled) {
+                                    WriteLine = false;
+                                }
+                            }
+                            CurrentToken = TokenEnd;
+                            continue;
+                        } else {
+                            WriteLine = true;
+                            CurrentToken = TokenEnd;
+                            continue;
+                        }
+                        break;
+                    case TokenSpace:
+                        break;
+                    case TokenPeriod:
+                        Command = true;
+                        break;
+                    default:
+                        WriteLine = true;
+                        CurrentToken = TokenEnd;
+                        continue;
+                }
+                NextToken();
+            }
+            if (WriteLine) {
+                WriteInfLine(Line);
+            }
+        } else {
+            while (CurrentToken != TokenEnd) {
+                switch (CurrentToken) {
+                case TokenInteger:
+                    sprintf(CurrentString, "%d", CurrentInteger);
+                case TokenIdentifier:
+                    if (Command) {
+                        /* Command */
+                        Status = PerformCommand();
+    
+                        if (Status == CAB_STATUS_FAILURE) {
+                            printf("Directive file contains errors at line %d.\n", (unsigned int)CurrentLine);
+                            DPRINT(MID_TRACE, ("Error while executing command.\n"));
+                        }
+    
+                        if (Status != CAB_STATUS_SUCCESS)
+                            return Status;
+                    } else {
+                        /* File copy */
+                        Status = PerformFileCopy();
+    
+                        if (Status == CAB_STATUS_FAILURE) {
+                            printf("Directive file contains errors at line %d.\n", (unsigned int)CurrentLine);
+                            DPRINT(MID_TRACE, ("Error while copying file.\n"));
+                        }
+    
+                        if (Status != CAB_STATUS_SUCCESS)
+                            return Status;
+                    }
+                    break;
+                case TokenSpace:
+                    break;
+                case TokenSemi:
+                    CurrentToken = TokenEnd;
+                    continue;
+                case TokenPeriod:
+                    Command = true;
+                    break;
+                default:
+                    printf("Directive file contains errors at line %d.\n", (unsigned int)CurrentLine);
+                    DPRINT(MID_TRACE, ("Token is (%d).\n", (unsigned int)CurrentToken));
+                    return CAB_STATUS_SUCCESS;
+                }
+                NextToken();
+            }
+        }
+    }
+
+    if (!InfFileOnly) {
+         printf("\nWriting cabinet. This may take a while...\n\n");
+    
+        if (DiskCreated) {
+            Status = WriteDisk(false);
+            if (Status == CAB_STATUS_SUCCESS)
+                Status = CloseDisk();
+            if (Status != CAB_STATUS_SUCCESS) {
+                DPRINT(MIN_TRACE, ("Cannot write disk (%d).\n", (unsigned int)Status));
+                return Status;
+            }
+        }
+    
+        if (CabinetCreated) {
+            Status = CloseCabinet();
+            if (Status != CAB_STATUS_SUCCESS) {
+                DPRINT(MIN_TRACE, ("Cannot close cabinet (%d).\n", (unsigned int)Status));
+                return Status;
+            }
+        }
+
+           printf("\nDone.\n");
+    }
+
+    return CAB_STATUS_SUCCESS;
+}
+
+
+bool CDFParser::OnDiskLabel(unsigned long Number, char* Label)
+/*
+ * FUNCTION: Called when a disk needs a label
+ * ARGUMENTS:
+ *     Number = Cabinet number that needs a label
+ *     Label  = Pointer to buffer to place label of disk
+ * RETURNS:
+ *     true if a disk label was returned, false if not
+ */
+{
+    char Buffer[20];
+    int i, j;
+    char ch;
+
+    Number += 1;
+
+    DPRINT(MID_TRACE, ("Giving disk (%d) a label...\n", (unsigned int)Number));
+
+    if (GetDiskName(&DiskLabel, Number, Label))
+        return true;
+
+    if (DiskLabelTemplateSet) {
+        j = 0;
+        strcpy(Label, "");
+        for (i = 0; i < strlen(DiskLabelTemplate); i++) {
+            ch = DiskLabelTemplate[i];
+            if (ch == '*') {
+                sprintf(Buffer, "%d", Number);
+                strcat(Label, Buffer);
+                j += strlen(Buffer);
+            } else {
+                Label[j] = ch;
+                j++;
+            }
+            Label[j] = '\0';
+        }
+
+        DPRINT(MID_TRACE, ("Giving disk (%s) as a label...\n", Label));
+
+        return true;
+    } else
+        return false;
+}
+
+
+bool CDFParser::OnCabinetName(unsigned long Number, char* Name)
+/*
+ * FUNCTION: Called when a cabinet needs a name
+ * ARGUMENTS:
+ *     Number = Disk number that needs a name
+ *     Name   = Pointer to buffer to place name of cabinet
+ * RETURNS:
+ *     true if a cabinet name was returned, false if not
+ */
+{
+    char Buffer[MAX_PATH];
+    int i, j;
+    char ch;
+
+    Number += 1;
+
+    DPRINT(MID_TRACE, ("Giving cabinet (%d) a name...\n", (unsigned int)Number));
+
+    if (GetDiskName(&CabinetName, Number, Buffer)) {
+        strcpy(Name, GetDestinationPath());
+        strcat(Name, Buffer);
+        return true;
+    }
+
+    if (CabinetNameTemplateSet) {
+        strcpy(Name, GetDestinationPath());
+        j = strlen(Name);
+        for (i = 0; i < strlen(CabinetNameTemplate); i++) {
+            ch = CabinetNameTemplate[i];
+            if (ch == '*') {
+                sprintf(Buffer, "%d", Number);
+                strcat(Name, Buffer);
+                j += strlen(Buffer);
+            } else {
+                Name[j] = ch;
+                j++;
+            }
+            Name[j] = '\0';
+        }
+
+        DPRINT(MID_TRACE, ("Giving cabinet (%s) as a name...\n", Name));
+        return true;
+    } else {
+        return false;
+    }
+}
+
+
+bool CDFParser::SetDiskName(PCABINET_NAME *List, unsigned long Number, char* String)
+/*
+ * FUNCTION: Sets an entry in a list
+ * ARGUMENTS:
+ *     List   = Address of pointer to list
+ *     Number = Disk number
+ *     String = Pointer to string
+ * RETURNS:
+ *     false if there was not enough free memory available
+ */
+{
+    PCABINET_NAME CN;
+
+    CN = *List;
+    while (CN != NULL) {
+        if (CN->DiskNumber == Number) {
+            strcpy(CN->Name, String);
+            return true;
+        }
+        CN = CN->Next;
+    }
+
+    CN = (PCABINET_NAME)AllocateMemory(sizeof(CABINET_NAME));
+    if (!CN)
+        return false;
+
+    CN->DiskNumber = Number;
+    strcpy(CN->Name, String);
+
+    CN->Next = *List;
+    *List = CN;
+
+    return true;
+}
+
+
+bool CDFParser::GetDiskName(PCABINET_NAME *List, unsigned long Number, char* String)
+/*
+ * FUNCTION: Returns an entry in a list
+ * ARGUMENTS:
+ *     List   = Address of pointer to list
+ *     Number = Disk number
+ *     String = Address of buffer to copy string to
+ * RETURNS:
+ *     false if there was not enough free memory available
+ */
+{
+    PCABINET_NAME CN;
+
+    CN = *List;
+    while (CN != NULL) {
+        if (CN->DiskNumber == Number) {
+            strcpy(String, CN->Name);
+            return true;
+        }
+        CN = CN->Next;
+    }
+
+    return false;
+}
+
+
+bool CDFParser::SetDiskNumber(PDISK_NUMBER *List, unsigned long Number, unsigned long Value)
+/*
+ * FUNCTION: Sets an entry in a list
+ * ARGUMENTS:
+ *     List   = Address of pointer to list
+ *     Number = Disk number
+ *     Value  = Value to set
+ * RETURNS:
+ *     false if there was not enough free memory available
+ */
+{
+    PDISK_NUMBER DN;
+
+    DN = *List;
+    while (DN != NULL) {
+        if (DN->DiskNumber == Number) {
+            DN->Number = Value;
+            return true;
+        }
+        DN = DN->Next;
+    }
+
+    DN = (PDISK_NUMBER)AllocateMemory(sizeof(DISK_NUMBER));
+    if (!DN)
+        return false;
+
+    DN->DiskNumber = Number;
+    DN->Number = Value;
+
+    DN->Next = *List;
+    *List = DN;
+
+    return true;
+}
+
+
+bool CDFParser::GetDiskNumber(PDISK_NUMBER *List, unsigned long Number, unsigned long* Value)
+/*
+ * FUNCTION: Returns an entry in a list
+ * ARGUMENTS:
+ *     List   = Address of pointer to list
+ *     Number = Disk number
+ *     Value  = Address of buffer to place value
+ * RETURNS:
+ *     true if the entry was found
+ */
+{
+    PDISK_NUMBER DN;
+
+    DN = *List;
+    while (DN != NULL) {
+        if (DN->DiskNumber == Number) {
+            *Value = DN->Number;
+            return true;
+        }
+        DN = DN->Next;
+    }
+
+    return false;
+}
+
+
+bool CDFParser::DoDiskLabel(unsigned long Number, char* Label)
+/*
+ * FUNCTION: Sets the label of a disk
+ * ARGUMENTS:
+ *     Number = Disk number
+ *     Label  = Pointer to label of disk
+ * RETURNS:
+ *     false if there was not enough free memory available
+ */
+{
+    DPRINT(MID_TRACE, ("Setting label of disk (%d) to '%s'\n", (unsigned int)Number, Label));
+
+    return SetDiskName(&DiskLabel, Number, Label);
+}
+
+
+void CDFParser::DoDiskLabelTemplate(char* Template)
+/*
+ * FUNCTION: Sets a disk label template to use
+ * ARGUMENTS:
+ *     Template = Pointer to disk label template
+ */
+{
+    DPRINT(MID_TRACE, ("Setting disk label template to '%s'\n", Template));
+
+    strcpy(DiskLabelTemplate, Template);
+    DiskLabelTemplateSet = true;
+}
+
+
+bool CDFParser::DoCabinetName(unsigned long Number, char* Name)
+/*
+ * FUNCTION: Sets the name of a cabinet
+ * ARGUMENTS:
+ *     Number = Disk number
+ *     Name   = Pointer to name of cabinet
+ * RETURNS:
+ *     false if there was not enough free memory available
+ */
+{
+    DPRINT(MID_TRACE, ("Setting name of cabinet (%d) to '%s'\n", (unsigned int)Number, Name));
+
+    return SetDiskName(&CabinetName, Number, Name);
+}
+
+
+void CDFParser::DoCabinetNameTemplate(char* Template)
+/*
+ * FUNCTION: Sets a cabinet name template to use
+ * ARGUMENTS:
+ *     Template = Pointer to cabinet name template
+ */
+{
+    DPRINT(MID_TRACE, ("Setting cabinet name template to '%s'\n", Template));
+
+    strcpy(CabinetNameTemplate, Template);
+    CabinetNameTemplateSet = true;
+}
+
+
+unsigned long CDFParser::DoMaxDiskSize(bool NumberValid, unsigned long Number)
+/*
+ * FUNCTION: Sets the maximum disk size
+ * ARGUMENTS:
+ *     NumberValid = true if disk number is valid
+ *     Number      = Disk number
+ * RETURNS:
+ *     Status of operation
+ * NOTES:
+ *     Standard sizes are 2.88M, 1.44M, 1.25M, 1.2M, 720K, 360K, and CDROM
+ */
+{
+    unsigned long A, B, Value;
+
+    if (IsNextToken(TokenInteger, true)) {
+
+        A = CurrentInteger;
+
+        if (IsNextToken(TokenPeriod, false)) {
+            if (!IsNextToken(TokenInteger, false))
+                return CAB_STATUS_FAILURE;
+
+            B = CurrentInteger;
+
+        } else
+            B = 0;
+
+        if (CurrentToken == TokenIdentifier) {
+            switch (CurrentString[0]) {
+            case 'K':
+                if (B != 0)
+                    return CAB_STATUS_FAILURE;
+
+                if (A == 720)
+                    /* 720K disk */
+                    Value = 730112;
+                else if (A == 360)
+                    /* 360K disk */
+                    Value = 362496;
+                else
+                    return CAB_STATUS_FAILURE;
+                break;
+            case 'M':
+                if (A == 1) {
+                    if (B == 44)
+                        /* 1.44M disk */
+                        Value = 1457664;
+                    else if (B == 25)
+                        /* 1.25M disk */
+                        Value = 1300000; // FIXME: Value?
+                    else if (B == 2)
+                        /* 1.2M disk */
+                        Value = 1213952;
+                    else
+                        return CAB_STATUS_FAILURE;
+                } else if (A == 2) {
+                    if (B == 88)
+                        /* 2.88M disk */
+                        Value = 2915328;
+                    else
+                        return CAB_STATUS_FAILURE;
+                } else
+                    return CAB_STATUS_FAILURE;
+                break;
+            default:
+                DPRINT(MID_TRACE, ("Bad suffix (%c)\n", CurrentString[0]));
+                return CAB_STATUS_FAILURE;
+            }
+        } else
+            Value = A;
+    } else {
+        if ((CurrentToken != TokenString) &&
+            (strcasecmp(CurrentString, "CDROM") != 0))
+            return CAB_STATUS_FAILURE;
+        /* CDROM */
+        Value = 640*1024*1024;  // FIXME: Correct size for CDROM?
+    }
+
+    if (NumberValid)
+        return (SetDiskNumber(&MaxDiskSize, Number, Value)?
+            CAB_STATUS_SUCCESS : CAB_STATUS_FAILURE);
+
+    MaxDiskSizeAll    = Value;
+    MaxDiskSizeAllSet = true;
+
+    SetMaxDiskSize(Value);
+
+    return CAB_STATUS_SUCCESS;
+}
+
+
+void CDFParser::DoInfFileName(char* FileName)
+/*
+ * FUNCTION: Sets filename of the generated .inf file
+ * ARGUMENTS:
+ *     FileName = Pointer to .inf filename
+ */
+{
+    DPRINT(MID_TRACE, ("Setting .inf filename to '%s'\n", FileName));
+
+    strcpy(InfFileName, FileName);
+    InfFileNameSet = true;
+}
+
+unsigned long CDFParser::SetupNewDisk()
+/*
+ * FUNCTION: Sets up parameters for a new disk
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    unsigned long Value;
+
+    if (!GetDiskNumber(&MaxDiskSize, GetCurrentDiskNumber(), &Value))  {
+        if (MaxDiskSizeAllSet)
+            Value = MaxDiskSizeAll;
+        else
+            Value = 0;
+    }
+    SetMaxDiskSize(Value);
+
+    return CAB_STATUS_SUCCESS;
+}
+
+
+unsigned long CDFParser::PerformSetCommand()
+/*
+ * FUNCTION: Performs a set variable command
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    SETTYPE SetType;
+    bool NumberValid = false;
+    unsigned long Number = 0;
+
+    if (!IsNextToken(TokenIdentifier, true))
+        return CAB_STATUS_FAILURE;
+
+    if (strcasecmp(CurrentString, "DiskLabel") == 0)
+        SetType = stDiskLabel;
+    else if (strcasecmp(CurrentString, "DiskLabelTemplate") == 0)
+        SetType = stDiskLabelTemplate;
+    else if (strcasecmp(CurrentString, "CabinetName") == 0)
+        SetType = stCabinetName;
+    else if (strcasecmp(CurrentString, "CabinetNameTemplate") == 0)
+        SetType = stCabinetNameTemplate;
+    else if (strcasecmp(CurrentString, "MaxDiskSize") == 0)
+        SetType = stMaxDiskSize;
+    else if (strcasecmp(CurrentString, "InfFileName") == 0)
+        SetType = stInfFileName;
+    else
+        return CAB_STATUS_FAILURE;
+
+    if ((SetType == stDiskLabel) || (SetType == stCabinetName)) {
+        if (!IsNextToken(TokenInteger, false))
+            return CAB_STATUS_FAILURE;
+        Number = CurrentInteger;
+
+        if (!IsNextToken(TokenEqual, true))
+            return CAB_STATUS_FAILURE;
+    } else if (SetType == stMaxDiskSize) {
+        if (IsNextToken(TokenInteger, false)) {
+            NumberValid = true;
+            Number = CurrentInteger;
+        } else {
+            NumberValid = false;
+            while (CurrentToken == TokenSpace)
+                NextToken();
+            if (CurrentToken != TokenEqual)
+                return CAB_STATUS_FAILURE;
+        }
+    } else if (!IsNextToken(TokenEqual, true))
+            return CAB_STATUS_FAILURE;
+
+    if (SetType != stMaxDiskSize) {
+        if (!IsNextToken(TokenString, true))
+            return CAB_STATUS_FAILURE;
+    }
+
+    switch (SetType) {
+    case stDiskLabel:
+        if (!DoDiskLabel(Number, CurrentString))
+            DPRINT(MIN_TRACE, ("Not enough available free memory.\n"));
+        return CAB_STATUS_SUCCESS;
+    case stCabinetName:
+        if (!DoCabinetName(Number, CurrentString))
+            DPRINT(MIN_TRACE, ("Not enough available free memory.\n"));
+        return CAB_STATUS_SUCCESS;
+    case stDiskLabelTemplate:
+        DoDiskLabelTemplate(CurrentString);
+        return CAB_STATUS_SUCCESS;
+    case stCabinetNameTemplate:
+        DoCabinetNameTemplate(CurrentString);
+        return CAB_STATUS_SUCCESS;
+    case stMaxDiskSize:
+        return DoMaxDiskSize(NumberValid, Number);
+    case stInfFileName:
+        DoInfFileName(CurrentString);
+        return CAB_STATUS_SUCCESS;
+    default:
+        return CAB_STATUS_FAILURE;
+    }
+}
+
+
+unsigned long CDFParser::PerformNewCommand()
+/*
+ * FUNCTION: Performs a new disk|cabinet|folder command
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    NEWTYPE NewType;
+    unsigned long Status;
+
+    if (!IsNextToken(TokenIdentifier, true))
+        return CAB_STATUS_FAILURE;
+
+    if (strcasecmp(CurrentString, "Disk") == 0)
+        NewType = ntDisk;
+    else if (strcasecmp(CurrentString, "Cabinet") == 0)
+        NewType = ntCabinet;
+    else if (strcasecmp(CurrentString, "Folder") == 0)
+        NewType = ntFolder;
+    else
+        return CAB_STATUS_FAILURE;
+
+    switch (NewType) {
+    case ntDisk:
+        if (DiskCreated) {
+            Status = WriteDisk(true);
+            if (Status == CAB_STATUS_SUCCESS)
+                Status = CloseDisk();
+            if (Status != CAB_STATUS_SUCCESS) {
+                DPRINT(MIN_TRACE, ("Cannot write disk (%d).\n", (unsigned int)Status));
+                return CAB_STATUS_SUCCESS;
+            }
+            DiskCreated = false;
+        }
+
+        Status = NewDisk();
+        if (Status != CAB_STATUS_SUCCESS) {
+            DPRINT(MIN_TRACE, ("Cannot create disk (%d).\n", (unsigned int)Status));
+            return CAB_STATUS_SUCCESS;
+        }
+        DiskCreated = true;
+        SetupNewDisk();
+        return CAB_STATUS_SUCCESS;
+    case ntCabinet:
+        if (DiskCreated) {
+            Status = WriteDisk(true);
+            if (Status == CAB_STATUS_SUCCESS)
+                Status = CloseDisk();
+            if (Status != CAB_STATUS_SUCCESS) {
+                DPRINT(MIN_TRACE, ("Cannot write disk (%d).\n", (unsigned int)Status));
+                return CAB_STATUS_SUCCESS;
+            }
+            DiskCreated = false;
+        }
+
+        Status = NewCabinet();
+        if (Status != CAB_STATUS_SUCCESS) {
+            DPRINT(MIN_TRACE, ("Cannot create cabinet (%d).\n", (unsigned int)Status));
+            return CAB_STATUS_SUCCESS;
+        }
+        DiskCreated = true;
+        SetupNewDisk();
+        return CAB_STATUS_SUCCESS;
+    case ntFolder:
+        Status = NewFolder();
+               ASSERT(Status == CAB_STATUS_SUCCESS);
+               return CAB_STATUS_SUCCESS;
+    default:
+        return CAB_STATUS_FAILURE;
+    }
+}
+
+
+unsigned long CDFParser::PerformInfBeginCommand()
+/*
+ * FUNCTION: Begins inf mode
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    InfModeEnabled = true;
+         return CAB_STATUS_SUCCESS;
+}
+
+
+unsigned long CDFParser::PerformInfEndCommand()
+/*
+ * FUNCTION: Begins inf mode
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    InfModeEnabled = false;
+         return CAB_STATUS_SUCCESS;
+}
+
+
+unsigned long CDFParser::PerformCommand()
+/*
+ * FUNCTION: Performs a command
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    if (strcasecmp(CurrentString, "Set") == 0)
+        return PerformSetCommand();
+    if (strcasecmp(CurrentString, "New") == 0)
+        return PerformNewCommand();
+    if (strcasecmp(CurrentString, "InfBegin") == 0)
+        return PerformInfBeginCommand();
+    if (strcasecmp(CurrentString, "InfEnd") == 0)
+        return PerformInfEndCommand();
+
+    return CAB_STATUS_FAILURE;
+}
+
+
+unsigned long CDFParser::PerformFileCopy()
+/*
+ * FUNCTION: Performs a file copy
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    unsigned long Status;
+    unsigned long i, j;
+    char ch;
+    char SrcName[MAX_PATH];
+    char DstName[MAX_PATH];
+    char InfLine[MAX_PATH];
+
+    strcpy(SrcName, "");
+    strcpy(DstName, "");
+
+    i = strlen(CurrentString);
+    while ((i < LineLength) &&
+        ((ch = Line[i]) != ' ') &&
+         (ch != 0x09) &&
+         (ch != ';')) {
+        CurrentString[i] = ch;
+        i++;
+    }
+    CurrentString[i] = '\0';
+    CurrentToken = TokenString;
+    CurrentChar  = i + 1;
+    strcpy(SrcName, CurrentString);
+
+    SkipSpaces();
+
+    if (CurrentToken != TokenEnd) {
+        j = strlen(CurrentString); i = 0;
+        while ((CurrentChar + i < LineLength) &&
+            ((ch = Line[CurrentChar + i]) != ' ') &&
+             (ch != 0x09) &&
+             (ch != ';')) {
+            CurrentString[j + i] = ch;
+            i++;
+        }
+        CurrentString[j + i] = '\0';
+        CurrentToken = TokenString;
+        CurrentChar += i + 1;
+        strcpy(DstName, CurrentString);
+    }
+
+    if (!CabinetCreated) {
+
+        DPRINT(MID_TRACE, ("Creating cabinet.\n"));
+
+        Status = NewCabinet();
+        if (Status != CAB_STATUS_SUCCESS) {
+            DPRINT(MIN_TRACE, ("Cannot create cabinet (%d).\n", (unsigned int)Status));
+            printf("Cannot create cabinet.\n");
+            return CAB_STATUS_FAILURE;
+        }
+        CabinetCreated = true;
+
+        DPRINT(MID_TRACE, ("Creating disk.\n"));
+
+        Status = NewDisk();
+        if (Status != CAB_STATUS_SUCCESS) {
+            DPRINT(MIN_TRACE, ("Cannot create disk (%d).\n", (unsigned int)Status));
+            printf("Cannot create disk.\n");
+            return CAB_STATUS_FAILURE;
+        }
+        DiskCreated = true;
+        SetupNewDisk();
+    }
+
+    DPRINT(MID_TRACE, ("Adding file: '%s'   destination: '%s'.\n", SrcName, DstName));
+
+    sprintf(InfLine, "%s=%s", GetFileName(SrcName), DstName);
+    WriteInfLine(InfLine);
+
+    Status = AddFile(SrcName);
+    if (Status != CAB_STATUS_SUCCESS) {
+        if (Status == CAB_STATUS_CANNOT_OPEN)
+                   printf("File does not exist: %s.\n", SrcName);
+        else if (Status == CAB_STATUS_NOMEMORY)
+            printf("Insufficient memory to add file: %s.\n", SrcName);
+        else
+            printf("Cannot add file: %s (%d).\n", SrcName, Status);
+        return Status;
+    }
+
+    return CAB_STATUS_SUCCESS;
+}
+
+
+void CDFParser::SkipSpaces()
+/*
+ * FUNCTION: Skips any spaces in the current line
+ */
+{
+    NextToken();
+    while (CurrentToken == TokenSpace)
+        NextToken();
+}
+
+
+bool CDFParser::IsNextToken(TOKEN Token, bool NoSpaces)
+/*
+ * FUNCTION: Checks if next token equals Token
+ * ARGUMENTS:
+ *     Token  = Token to compare with
+ *     SkipSp = true if spaces should be skipped
+ * RETURNS:
+ *     false if next token is diffrent from Token
+ */
+{
+    if (NoSpaces)
+        SkipSpaces();
+    else
+        NextToken();
+    return (CurrentToken == Token);
+}
+
+
+bool CDFParser::ReadLine()
+/*
+ * FUNCTION: Reads the next line into the line buffer
+ * RETURNS:
+ *     true if there is a new line, false if not
+ */
+{
+    unsigned long i, j;
+    char ch;
+
+    if (CurrentOffset >= FileBufferSize)
+        return false;
+
+    i = 0;
+    while (((j = CurrentOffset + i) < FileBufferSize) && (i < 127) &&
+        ((ch = FileBuffer[j]) != 0x0D && (ch = FileBuffer[j]) != 0x0A)) {
+        Line[i] = ch;
+        i++;
+    }
+
+    Line[i]    = '\0';
+    LineLength = i;
+
+    if ((FileBuffer[CurrentOffset + i] == 0x0D) && (FileBuffer[CurrentOffset + i + 1] == 0x0A))
+        CurrentOffset++;
+
+    CurrentOffset += i + 1;
+
+    CurrentChar = 0;
+
+    CurrentLine++;
+
+    NextToken();
+
+    return true;
+}
+
+
+void CDFParser::NextToken()
+/*
+ * FUNCTION: Reads the next token from the current line
+ */
+{
+    unsigned long i;
+    char ch = ' ';
+
+    if (CurrentChar >= LineLength) {
+        CurrentToken = TokenEnd;
+        return;
+    }
+
+    switch (Line[CurrentChar]) {
+    case ' ':
+    case 0x09: CurrentToken = TokenSpace;
+        break;
+    case ';': CurrentToken = TokenSemi;
+        break;
+    case '=': CurrentToken = TokenEqual;
+        break;
+    case '.': CurrentToken = TokenPeriod;
+        break;
+    case '\\': CurrentToken = TokenBackslash;
+        break;
+    case '"':
+        i = 0;
+        while ((CurrentChar + i + 1 < LineLength) &&
+            ((ch = Line[CurrentChar + i + 1]) != '"')) {
+            CurrentString[i] = ch;
+            i++;
+        }
+        CurrentString[i] = '\0';
+        CurrentToken = TokenString;
+        CurrentChar += i + 2;
+        return;
+    default:
+        i = 0;
+        while ((CurrentChar + i < LineLength) &&
+            ((ch = Line[CurrentChar + i]) >= '0') && (ch <= '9')) {
+            CurrentString[i] = ch;
+            i++;
+        }
+        if (i > 0) {
+            CurrentString[i] = '\0';
+            CurrentInteger = atoi((char*)CurrentString);
+            CurrentToken = TokenInteger;
+            CurrentChar += i;
+            return;
+        }
+        i = 0;
+        while (((CurrentChar + i < LineLength) &&
+            (((ch = Line[CurrentChar + i]) >= 'a') && (ch <= 'z')) ||
+            ((ch >= 'A') && (ch <= 'Z')) || (ch == '_'))) {
+            CurrentString[i] = ch;
+            i++;
+        }
+        if (i > 0) {
+            CurrentString[i] = '\0';
+            CurrentToken = TokenIdentifier;
+            CurrentChar += i;
+            return;
+        }
+        CurrentToken = TokenEnd;
+    }
+    CurrentChar++;
+}
+
+/* EOF */