Task 042: .ASPX File Format

Task 042: .ASPX File Format

Understanding the .ASPX File Format

Before addressing the task, it’s important to clarify that .ASPX (Active Server Page Extended) is not a traditional file format with intrinsic file system properties like binary formats (e.g., .jpg or .pdf). Instead, it is a server-side web page format used within Microsoft’s ASP.NET framework to generate dynamic web content. An .ASPX file is essentially a text-based file containing a mix of HTML, server-side scripts (typically in C# or VB.NET), and ASP.NET-specific directives or controls. These files are processed by a web server (e.g., Microsoft IIS) to produce HTML output for browsers. Therefore, the "properties intrinsic to its file system" are limited to typical file metadata, as the content and behavior are defined by the ASP.NET runtime rather than a rigid file structure.

1. List of Properties Intrinsic to the .ASPX File Format in the File System

Since .ASPX files are text-based and lack a specific binary structure, their intrinsic file system properties are those associated with any text file. Based on the nature of .ASPX files and standard file system metadata, the relevant properties are:

  • File Name: The name of the .ASPX file (e.g., index.aspx).
  • File Extension: The .aspx extension, indicating it is an ASP.NET web form.
  • File Size: The size of the file in bytes.
  • Creation Time: The timestamp when the file was created.
  • Last Modified Time: The timestamp when the file was last modified.
  • Last Accessed Time: The timestamp when the file was last accessed.
  • File Path: The absolute or relative path to the file in the file system.
  • File Permissions: Access control settings (e.g., read, write, execute permissions).
  • Content Type: Typically text/html or application/xhtml+xml, as .ASPX files are served as web content.
  • Encoding: The character encoding of the file, usually UTF-8 for modern ASP.NET applications.
  • File Attributes: System-specific attributes like hidden, read-only, or system file flags.

These properties are not unique to .ASPX files but apply to any file in a file system. The actual content of an .ASPX file (HTML, server-side scripts, and ASP.NET directives) is interpreted at runtime by the ASP.NET framework and does not constitute fixed file system properties. Since .ASPX files are text-based, they can be read and written like any text file, but their dynamic behavior requires a server environment to execute.

2. Python Class for .ASPX File Handling

Below is a Python class that opens, reads, writes, and prints the file system properties of an .ASPX file. Since .ASPX files are text-based, the class uses standard file operations and the os module to retrieve file system metadata.

import os
import mimetypes
import time

class ASPXFileHandler:
    def __init__(self, file_path):
        self.file_path = file_path
        self.properties = {}

    def get_file_properties(self):
        """Retrieve file system properties of the .ASPX file."""
        try:
            # Get file statistics
            stats = os.stat(self.file_path)
            
            # File name and extension
            self.properties['file_name'] = os.path.basename(self.file_path)
            self.properties['file_extension'] = os.path.splitext(self.file_path)[1].lower()
            
            # File size
            self.properties['file_size'] = stats.st_size
            
            # Timestamps
            self.properties['creation_time'] = time.ctime(stats.st_ctime)
            self.properties['last_modified_time'] = time.ctime(stats.st_mtime)
            self.properties['last_accessed_time'] = time.ctime(stats.st_atime)
            
            # File path
            self.properties['file_path'] = os.path.abspath(self.file_path)
            
            # File permissions (octal format)
            self.properties['file_permissions'] = oct(stats.st_mode)[-3:]
            
            # Content type
            content_type, _ = mimetypes.guess_type(self.file_path)
            self.properties['content_type'] = content_type or 'text/html'
            
            # Encoding (assuming UTF-8 for .ASPX, could be detected more robustly)
            self.properties['encoding'] = 'utf-8'
            
            # File attributes (Windows-specific or general)
            self.properties['file_attributes'] = 'directory' if os.path.isdir(self.file_path) else 'regular file'
            
        except FileNotFoundError:
            print(f"Error: File {self.file_path} not found.")
        except Exception as e:
            print(f"Error retrieving properties: {e}")

    def read_file(self):
        """Read the content of the .ASPX file."""
        try:
            with open(self.file_path, 'r', encoding='utf-8') as file:
                content = file.read()
                return content
        except FileNotFoundError:
            print(f"Error: File {self.file_path} not found.")
            return None
        except Exception as e:
            print(f"Error reading file: {e}")
            return None

    def write_file(self, content):
        """Write content to the .ASPX file."""
        try:
            with open(self.file_path, 'w', encoding='utf-8') as file:
                file.write(content)
            print(f"Successfully wrote to {self.file_path}")
        except Exception as e:
            print(f"Error writing to file: {e}")

    def print_properties(self):
        """Print all file system properties."""
        if not self.properties:
            self.get_file_properties()
        for key, value in self.properties.items():
            print(f"{key}: {value}")

# Example usage
if __name__ == "__main__":
    aspx_file = ASPXFileHandler("example.aspx")
    aspx_file.get_file_properties()
    aspx_file.print_properties()
    
    # Read and display file content
    content = aspx_file.read_file()
    if content:
        print("\nFile Content:")
        print(content)
    
    # Write new content (example)
    new_content = "<%@ Page Language='C#' %>\n<html>\n<body>\n<h1>Hello, ASP.NET!</h1>\n</body>\n</html>"
    aspx_file.write_file(new_content)

Notes:

  • This class assumes the .ASPX file is accessible locally and treats it as a text file.
  • It uses the os module to retrieve file system metadata and mimetypes to guess the content type.
  • The read_file method reads the file content as UTF-8 text, and write_file allows overwriting or creating a new .ASPX file.
  • The class does not execute the server-side code, as that requires an ASP.NET runtime environment (e.g., IIS).

3. Java Class for .ASPX File Handling

Below is a Java class that performs similar operations using Java’s file handling capabilities.

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;

public class ASPXFileHandler {
    private String filePath;
    private Map<String, String> properties;

    public ASPXFileHandler(String filePath) {
        this.filePath = filePath;
        this.properties = new HashMap<>();
    }

    public void getFileProperties() {
        try {
            Path path = Paths.get(filePath);
            BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);

            // File name and extension
            properties.put("file_name", path.getFileName().toString());
            properties.put("file_extension", filePath.substring(filePath.lastIndexOf(".")).toLowerCase());

            // File size
            properties.put("file_size", String.valueOf(attrs.size()) + " bytes");

            // Timestamps
            properties.put("creation_time", attrs.creationTime().toString());
            properties.put("last_modified_time", attrs.lastModifiedTime().toString());
            properties.put("last_accessed_time", attrs.lastAccessTime().toString());

            // File path
            properties.put("file_path", path.toAbsolutePath().toString());

            // File permissions (simplified)
            properties.put("file_permissions", 
                (Files.isReadable(path) ? "r" : "-") +
                (Files.isWritable(path) ? "w" : "-") +
                (Files.isExecutable(path) ? "x" : "-"));

            // Content type (hardcoded for .aspx)
            properties.put("content_type", "text/html");

            // Encoding
            properties.put("encoding", "UTF-8");

            // File attributes
            properties.put("file_attributes", attrs.isDirectory() ? "directory" : "regular file");

        } catch (IOException e) {
            System.err.println("Error retrieving properties: " + e.getMessage());
        }
    }

    public String readFile() {
        try {
            return new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
        } catch (IOException e) {
            System.err.println("Error reading file: " + e.getMessage());
            return null;
        }
    }

    public void writeFile(String content) {
        try {
            Files.write(Paths.get(filePath), content.getBytes(StandardCharsets.UTF_8));
            System.out.println("Successfully wrote to " + filePath);
        } catch (IOException e) {
            System.err.println("Error writing to file: " + e.getMessage());
        }
    }

    public void printProperties() {
        if (properties.isEmpty()) {
            getFileProperties();
        }
        for (Map.Entry<String, String> entry : properties.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }

    public static void main(String[] args) {
        ASPXFileHandler handler = new ASPXFileHandler("example.aspx");
        handler.getFileProperties();
        handler.printProperties();

        // Read and display file content
        String content = handler.readFile();
        if (content != null) {
            System.out.println("\nFile Content:");
            System.out.println(content);
        }

        // Write new content (example)
        String newContent = "<%@ Page Language=\"C#\" %>\n<html>\n<body>\n<h1>Hello, ASP.NET!</h1>\n</body>\n</html>";
        handler.writeFile(newContent);
    }
}

Notes:

  • Uses java.nio.file for file system metadata and file operations.
  • Assumes UTF-8 encoding for reading and writing.
  • Handles exceptions for file access and provides basic permission information.

4. JavaScript Class for .ASPX File Handling (Node.js)

Since JavaScript typically runs in a browser or Node.js environment, this class uses Node.js’s fs module for file system operations.

const fs = require('fs').promises;
const path = require('path');
const mime = require('mime-types');

class ASPXFileHandler {
    constructor(filePath) {
        this.filePath = filePath;
        this.properties = {};
    }

    async getFileProperties() {
        try {
            const stats = await fs.stat(this.filePath);

            // File name and extension
            this.properties.file_name = path.basename(this.filePath);
            this.properties.file_extension = path.extname(this.filePath).toLowerCase();

            // File size
            this.properties.file_size = `${stats.size} bytes`;

            // Timestamps
            this.properties.creation_time = stats.birthtime.toISOString();
            this.properties.last_modified_time = stats.mtime.toISOString();
            this.properties.last_accessed_time = stats.atime.toISOString();

            // File path
            this.properties.file_path = path.resolve(this.filePath);

            // File permissions (simplified)
            this.properties.file_permissions = (stats.mode & 0o777).toString(8);

            // Content type
            this.properties.content_type = mime.lookup(this.filePath) || 'text/html';

            // Encoding
            this.properties.encoding = 'utf-8';

            // File attributes
            this.properties.file_attributes = stats.isDirectory() ? 'directory' : 'regular file';

        } catch (error) {
            console.error(`Error retrieving properties: ${error.message}`);
        }
    }

    async readFile() {
        try {
            return await fs.readFile(this.filePath, 'utf-8');
        } catch (error) {
            console.error(`Error reading file: ${error.message}`);
            return null;
        }
    }

    async writeFile(content) {
        try {
            await fs.writeFile(this.filePath, content, 'utf-8');
            console.log(`Successfully wrote to ${this.filePath}`);
        } catch (error) {
            console.error(`Error writing to file: ${error.message}`);
        }
    }

    async printProperties() {
        if (Object.keys(this.properties).length === 0) {
            await this.getFileProperties();
        }
        for (const [key, value] of Object.entries(this.properties)) {
            console.log(`${key}: ${value}`);
        }
    }
}

// Example usage
(async () => {
    const handler = new ASPXFileHandler('example.aspx');
    await handler.getFileProperties();
    await handler.printProperties();

    // Read and display file content
    const content = await handler.readFile();
    if (content) {
        console.log('\nFile Content:');
        console.log(content);
    }

    // Write new content (example)
    const newContent = `<%@ Page Language="C#" %>
<html>
<body>
<h1>Hello, ASP.NET!</h1>
</body>
</html>`;
    await handler.writeFile(newContent);
})();

Notes:

  • Requires Node.js and the mime-types package (npm install mime-types).
  • Uses asynchronous file operations with fs.promises.
  • Assumes UTF-8 encoding and uses mime-types to determine content type.

5. C Class for .ASPX File Handling

C does not have classes, so we’ll use a struct and functions to achieve similar functionality. This implementation uses standard C file operations and system calls for metadata.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>

#define MAX_PATH 256
#define MAX_CONTENT 1024

typedef struct {
    char file_path[MAX_PATH];
    char file_name[MAX_PATH];
    char file_extension[16];
    char file_size[32];
    char creation_time[64];
    char last_modified_time[64];
    char last_accessed_time[64];
    char file_permissions[16];
    char content_type[32];
    char encoding[16];
    char file_attributes[32];
} ASPXFileHandler;

void init_aspx_handler(ASPXFileHandler* handler, const char* file_path) {
    strncpy(handler->file_path, file_path, MAX_PATH - 1);
    handler->file_path[MAX_PATH - 1] = '\0';
}

void get_file_properties(ASPXFileHandler* handler) {
    struct stat stats;
    if (stat(handler->file_path, &stats) == -1) {
        printf("Error: File %s not found.\n", handler->file_path);
        return;
    }

    // File name and extension
    char* base_name = strrchr(handler->file_path, '/');
    if (!base_name) base_name = handler->file_path;
    else base_name++;
    strncpy(handler->file_name, base_name, MAX_PATH - 1);
    char* ext = strrchr(handler->file_name, '.');
    strncpy(handler->file_extension, ext ? ext : ".aspx", 15);

    // File size
    snprintf(handler->file_size, 32, "%ld bytes", stats.st_size);

    // Timestamps
    strftime(handler->creation_time, 64, "%Y-%m-%d %H:%M:%S", localtime(&stats.st_ctime));
    strftime(handler->last_modified_time, 64, "%Y-%m-%d %H:%M:%S", localtime(&stats.st_mtime));
    strftime(handler->last_accessed_time, 64, "%Y-%m-%d %H:%M:%S", localtime(&stats.st_atime));

    // File path
    char abs_path[MAX_PATH];
    realpath(handler->file_path, abs_path);
    strncpy(handler->file_path, abs_path, MAX_PATH - 1);

    // File permissions
    snprintf(handler->file_permissions, 16, "%o", stats.st_mode & 0777);

    // Content type (hardcoded)
    strcpy(handler->content_type, "text/html");

    // Encoding
    strcpy(handler->encoding, "utf-8");

    // File attributes
    strcpy(handler->file_attributes, S_ISDIR(stats.st_mode) ? "directory" : "regular file");
}

void read_file(ASPXFileHandler* handler) {
    FILE* file = fopen(handler->file_path, "r");
    if (!file) {
        printf("Error: Cannot read file %s\n", handler->file_path);
        return;
    }

    printf("\nFile Content:\n");
    char buffer[MAX_CONTENT];
    while (fgets(buffer, MAX_CONTENT, file)) {
        printf("%s", buffer);
    }
    fclose(file);
}

void write_file(ASPXFileHandler* handler, const char* content) {
    FILE* file = fopen(handler->file_path, "w");
    if (!file) {
        printf("Error: Cannot write to file %s\n", handler->file_path);
        return;
    }

    fputs(content, file);
    fclose(file);
    printf("Successfully wrote to %s\n", handler->file_path);
}

void print_properties(ASPXFileHandler* handler) {
    printf("file_name: %s\n", handler->file_name);
    printf("file_extension: %s\n", handler->file_extension);
    printf("file_size: %s\n", handler->file_size);
    printf("creation_time: %s\n", handler->creation_time);
    printf("last_modified_time: %s\n", handler->last_modified_time);
    printf("last_accessed_time: %s\n", handler->last_accessed_time);
    printf("file_path: %s\n", handler->file_path);
    printf("file_permissions: %s\n", handler->file_permissions);
    printf("content_type: %s\n", handler->content_type);
    printf("encoding: %s\n", handler->encoding);
    printf("file_attributes: %s\n", handler->file_attributes);
}

int main() {
    ASPXFileHandler handler;
    init_aspx_handler(&handler, "example.aspx");
    get_file_properties(&handler);
    print_properties(&handler);

    read_file(&handler);

    const char* new_content = "<%@ Page Language=\"C#\" %>\n<html>\n<body>\n<h1>Hello, ASP.NET!</h1>\n</body>\n</html>";
    write_file(&handler, new_content);

    return 0;
}

Notes:

  • Uses standard C libraries (stdio.h, sys/stat.h) for file operations and metadata.
  • Assumes UTF-8 encoding and hardcodes text/html as the content type.
  • Simplified permission handling using POSIX-style octal notation.

Additional Notes

  • Decoding and Execution: .ASPX files contain server-side code (e.g., C# or VB.NET) that requires an ASP.NET runtime (e.g., IIS) to execute. The classes above treat .ASPX files as text files and do not execute the server-side logic, as this is beyond the scope of simple file handling without a web server.
  • Limitations: The task assumes .ASPX files have intrinsic file system properties beyond typical file metadata, but their dynamic nature (processed by ASP.NET) means most "properties" are runtime behaviors, not static attributes. The classes focus on file system metadata and content access.
  • Sources: The implementation is based on general knowledge of .ASPX files as text-based web forms in ASP.NET, with metadata handling inspired by standard file system APIs. No specific external sources were required, as the properties and operations are standard for text files.

If you need further clarification or additional functionality (e.g., parsing ASP.NET directives or executing the files in a server context), please let me know!

.ASPX File Format Specifications

The .ASPX file format is a text-based format used for Active Server Pages Extended in Microsoft's ASP.NET framework. It is not a binary format but rather a markup file containing HTML, server-side controls, scripts, and directives processed by the ASP.NET runtime on web servers. The specifications are documented in Microsoft ASP.NET resources, focusing on syntax for page directives, controls, and code integration. The primary structural element is the @Page directive, which defines configuration attributes for the page compiler and parser. Files are typically encoded in UTF-8 and can reference code-behind files (.aspx.cs or .aspx.vb).

1. List of All Properties Intrinsic to the .ASPX File Format

Based on the format's specifications, the key properties are the attributes defined in the @Page directive, which are intrinsic to how the file is processed in the ASP.NET environment. These are not file system metadata but format-specific configurations embedded in the text. Here is the comprehensive list:

  • AutoEventWireup: Specifies if page events should be auto-wired.
  • ClassName: Specifies the class name that will be dynamically compiled when the page is requested.
  • CodeFile: Specifies the code-behind class for the current page.
  • CodeBehind: Specifies the path to the code-behind class for the current page.
  • CodeFileBaseClass: Specifies the type name of a base class for a page and its associated code-behind class.
  • CompilerOptions: Specifies compilation options for the current page.
  • Description: Specifies a text description of the master page.
  • Debug: Specifies if the page should be compiled with debug symbols.
  • Language: Specifies the language used when compiling inline code blocks.
  • Inherits: Specifies the base class for the page to inherit.
  • Src: Specifies the source file that contains the implementation of the base class specified with Inherits.
  • MasterPageFile: Specifies the master page for the current page.
  • EnableSessionState: Specifies how the page should treat session data (true, false, readonly).
  • EnableViewState: Specifies whether the page view state is maintained across page requests.
  • EnableTheming: Specifies if the page will support themes for embedded controls.
  • ErrorPage: Specifies the error page URL for unhandled page exceptions.
  • ValidateRequest: Specifies whether page request validation should occur.
  • CodePage: Specifies the code page value for the response.
  • ContentType: Specifies the HTTP content type of the page response.
  • Title: Specifies the title of the page.
  • ResponseEncoding: Specifies the character encoding of the page.
  • Buffer: Specifies the HTTP response buffer of the page.

Note: Not all properties are required in every .ASPX file; they are optional based on the page's configuration. The classes below will handle extracting and modifying these where present.

2. Python Class for .ASPX Files

import os
import re

class ASPXFile:
    def __init__(self, filepath):
        if not filepath.lower().endswith('.aspx'):
            raise ValueError("File must have .aspx extension")
        self.filepath = filepath
        self.properties = self._decode_properties()

    def _decode_properties(self):
        with open(self.filepath, 'r', encoding='utf-8') as f:
            content = f.read()
        # Find the @Page directive
        match = re.search(r'<%@\s*Page\s+(.*?)%>', content, re.IGNORECASE | re.DOTALL)
        if not match:
            return {}
        attr_str = match.group(1)
        # Parse attributes: key="value" or key='value' or key=value
        attrs = re.findall(r'(\w+)\s*=\s*(["\']?)(.*?)\2(?=\s+\w+=|\s*%>)', attr_str, re.DOTALL)
        return {key: value for key, _, value in attrs}

    def read_properties(self):
        return self.properties

    def write_properties(self, new_properties):
        with open(self.filepath, 'r', encoding='utf-8') as f:
            content = f.read()
        # Find existing directive
        match = re.search(r'(<%@\s*Page\s+).*?(%>)', content, re.IGNORECASE | re.DOTALL)
        if match:
            # Rebuild directive with new properties
            attr_str = ' '.join([f'{key}="{value}"' for key, value in new_properties.items()])
            new_directive = f'{match.group(1)}{attr_str}{match.group(2)}'
            content = content.replace(match.group(0), new_directive)
        else:
            # Add new directive at the top
            attr_str = ' '.join([f'{key}="{value}"' for key, value in new_properties.items()])
            new_directive = f'<%@ Page {attr_str} %>\n'
            content = new_directive + content
        with open(self.filepath, 'w', encoding='utf-8') as f:
            f.write(content)
        self.properties = new_properties

3. Java Class for .ASPX Files

import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.regex.*;

public class ASPXFile {
    private String filepath;
    private Map<String, String> properties;

    public ASPXFile(String filepath) throws IOException {
        if (!filepath.toLowerCase().endsWith(".aspx")) {
            throw new IllegalArgumentException("File must have .aspx extension");
        }
        this.filepath = filepath;
        this.properties = decodeProperties();
    }

    private Map<String, String> decodeProperties() throws IOException {
        String content = new String(Files.readAllBytes(Paths.get(filepath)), "UTF-8");
        Pattern pattern = Pattern.compile("<%@\\s*Page\\s+(.*?)%>", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
        Matcher matcher = pattern.matcher(content);
        if (!matcher.find()) {
            return new HashMap<>();
        }
        String attrStr = matcher.group(1);
        Map<String, String> attrs = new HashMap<>();
        Pattern attrPattern = Pattern.compile("(\\w+)\\s*=\\s*([\"']?)(.*?)\\2(?=\\s+\\w+=|\\s*%>)", Pattern.DOTALL);
        Matcher attrMatcher = attrPattern.matcher(attrStr);
        while (attrMatcher.find()) {
            attrs.put(attrMatcher.group(1), attrMatcher.group(3));
        }
        return attrs;
    }

    public Map<String, String> readProperties() {
        return new HashMap<>(properties);
    }

    public void writeProperties(Map<String, String> newProperties) throws IOException {
        String content = new String(Files.readAllBytes(Paths.get(filepath)), "UTF-8");
        Pattern pattern = Pattern.compile("(<%@\\s*Page\\s+).*?(%>)", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()) {
            StringBuilder attrStr = new StringBuilder();
            for (Map.Entry<String, String> entry : newProperties.entrySet()) {
                attrStr.append(entry.getKey()).append("=\"").append(entry.getValue()).append("\" ");
            }
            String newDirective = matcher.group(1) + attrStr.toString().trim() + matcher.group(2);
            content = content.replace(matcher.group(0), newDirective);
        } else {
            StringBuilder attrStr = new StringBuilder();
            for (Map.Entry<String, String> entry : newProperties.entrySet()) {
                attrStr.append(entry.getKey()).append("=\"").append(entry.getValue()).append("\" ");
            }
            String newDirective = "<%@ Page " + attrStr.toString().trim() + " %>\n";
            content = newDirective + content;
        }
        Files.write(Paths.get(filepath), content.getBytes("UTF-8"));
        this.properties = new HashMap<>(newProperties);
    }
}

4. JavaScript Class for .ASPX Files (Node.js)

const fs = require('fs');
const path = require('path');

class ASPXFile {
    constructor(filepath) {
        if (!filepath.toLowerCase().endsWith('.aspx')) {
            throw new Error('File must have .aspx extension');
        }
        this.filepath = filepath;
        this.properties = this._decodeProperties();
    }

    _decodeProperties() {
        const content = fs.readFileSync(this.filepath, 'utf-8');
        const match = content.match(/<%@\s*Page\s+(.*?)%>/is);
        if (!match) {
            return {};
        }
        const attrStr = match[1];
        const attrs = {};
        const attrMatches = attrStr.matchAll(/(\w+)\s*=\s*(["']?)(.*?)\2(?=\s+\w+=|\s*%>)/gs);
        for (const attrMatch of attrMatches) {
            attrs[attrMatch[1]] = attrMatch[3];
        }
        return attrs;
    }

    readProperties() {
        return { ...this.properties };
    }

    writeProperties(newProperties) {
        let content = fs.readFileSync(this.filepath, 'utf-8');
        const match = content.match(/(<%@\s*Page\s+).*?(%>)/is);
        if (match) {
            const attrStr = Object.entries(newProperties)
                .map(([key, value]) => `${key}="${value}"`)
                .join(' ');
            const newDirective = `${match[1]}${attrStr}${match[2]}`;
            content = content.replace(match[0], newDirective);
        } else {
            const attrStr = Object.entries(newProperties)
                .map(([key, value]) => `${key}="${value}"`)
                .join(' ');
            const newDirective = `<%@ Page ${attrStr} %>\n`;
            content = newDirective + content;
        }
        fs.writeFileSync(this.filepath, content, 'utf-8');
        this.properties = { ...newProperties };
    }
}

module.exports = ASPXFile;

5. C++ Class for .ASPX Files

#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <regex>
#include <algorithm>
#include <cctype>

class ASPXFile {
private:
    std::string filepath;
    std::map<std::string, std::string> properties;

    std::map<std::string, std::string> decodeProperties() {
        std::ifstream file(filepath, std::ios::in);
        if (!file.is_open()) {
            throw std::runtime_error("Unable to open file");
        }
        std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
        file.close();

        std::regex directiveRegex(R"(<\%\@\s*Page\s+(.*?)\%\>)", std::regex::icase | std::regex::ECMAScript);
        std::smatch match;
        if (!std::regex_search(content, match, directiveRegex)) {
            return {};
        }
        std::string attrStr = match[1].str();

        std::map<std::string, std::string> attrs;
        std::regex attrRegex(R"((\w+)\s*=\s*(["']?)(.*?)\2(?=\s+\w+=|\s*\%>))", std::regex::ECMAScript);
        auto attrsBegin = std::sregex_iterator(attrStr.begin(), attrStr.end(), attrRegex);
        auto attrsEnd = std::sregex_iterator();
        for (std::sregex_iterator i = attrsBegin; i != attrsEnd; ++i) {
            std::smatch attrMatch = *i;
            attrs[attrMatch[1].str()] = attrMatch[3].str();
        }
        return attrs;
    }

public:
    ASPXFile(const std::string& fp) : filepath(fp) {
        std::string ext = filepath.substr(filepath.find_last_of(".") + 1);
        std::transform(ext.begin(), ext.end(), ext.begin(),
            [](unsigned char c){ return std::tolower(c); });
        if (ext != "aspx") {
            throw std::invalid_argument("File must have .aspx extension");
        }
        properties = decodeProperties();
    }

    std::map<std::string, std::string> readProperties() const {
        return properties;
    }

    void writeProperties(const std::map<std::string, std::string>& newProperties) {
        std::ifstream fileIn(filepath, std::ios::in);
        if (!fileIn.is_open()) {
            throw std::runtime_error("Unable to open file");
        }
        std::string content((std::istreambuf_iterator<char>(fileIn)), std::istreambuf_iterator<char>());
        fileIn.close();

        std::regex directiveRegex(R"((<\%\@\s*Page\s+).*?(\%\>))", std::regex::icase | std::regex::ECMAScript);
        std::smatch match;
        if (std::regex_search(content, match, directiveRegex)) {
            std::string attrStr;
            for (const auto& pair : newProperties) {
                attrStr += pair.first + "=\"" + pair.second + "\" ";
            }
            if (!attrStr.empty()) attrStr.pop_back(); // Remove trailing space
            std::string newDirective = match[1].str() + attrStr + match[2].str();
            content = std::regex_replace(content, directiveRegex, newDirective, std::regex_constants::format_first_only);
        } else {
            std::string attrStr;
            for (const auto& pair : newProperties) {
                attrStr += pair.first + "=\"" + pair.second + "\" ";
            }
            if (!attrStr.empty()) attrStr.pop_back();
            std::string newDirective = "<%@ Page " + attrStr + " %>\n";
            content = newDirective + content;
        }

        std::ofstream fileOut(filepath, std::ios::out | std::ios::trunc);
        if (!fileOut.is_open()) {
            throw std::runtime_error("Unable to write to file");
        }
        fileOut << content;
        fileOut.close();
        properties = newProperties;
    }
};