N64-UNFLoader icon indicating copy to clipboard operation
N64-UNFLoader copied to clipboard

[Suggestion] Add syntax for uploading a portion of a file in UNFLoader.

Open DavidSM64 opened this issue 1 year ago • 1 comments

Expected Behavior

Currently, you can only upload an entire binary file by surrounding a path with @ symbols when you send a command through UNFLoader. I'd like to be able to send a range of bytes of the file.

Possible Solution

I'm thinking it could be implemented like: @file.bin[start:end]@. The actual syntax doesn't really matter to me, just having the feature would be nice.

Context (Environment)

I recently added hot-reloading support to Diddy Kong Racing, in which I only reload the first megabyte of the ROM instead of the entire thing. During the building of the ROM, I added an extra step at the end to create a new file that contains only the first megabyte of the ROM to upload. I'm not actually monitoring if the ROM itself has changed for the hot reload, but instead I'm monitoring that copy.

Possible Implementation

debug_send() in UNFLoader/debug.c would need to be modified just before the fopen.

I made a function that can parse the range and should be easy to slot in:

/*==============================
    parse_file_range
    Parses out the file range syntax `[start:end]` for a given token if it exists.
    Note: end may be larger than the file size.
    @param token to parse (from debug_send). The range syntax will get removed after the function completes.
    @param The outputted start position of the file (0 by default)
    @param The outputted end position of the file. (4294967295 by default)
==============================*/
void parse_file_range(char *token, uint32_t *start, uint32_t *end)
{
    char *bracketOpen;
    char *bracketClose;
    char *colon;
    char *tokenEnd;
    char *number;
    
    bracketOpen  = strchr(token, '[');
    colon        = strchr(token, ':');
    bracketClose = strchr(token, ']');
    
    // Default values, representing the entire file.
    *start = 0;
    *end   = 4294967295; // Largest uint32_t value.
    
    // Check if there is a file range.
    if(!bracketOpen && !colon && !bracketClose) {
        return;
    }
    
    // Check for obvious syntax errors.
    if(!bracketOpen || !colon || !bracketClose || 
        (bracketClose < bracketOpen) || 
        (bracketClose < colon) || 
        (colon < bracketOpen)) 
    {
        terminate("Invalid file range syntax.");
    }
    
    // Fix token
    tokenEnd = bracketOpen;
    while(tokenEnd[-1] == ' ') tokenEnd--; // Exclude whitespace
    *tokenEnd = '\0'; // Make sure the token ends up being just the filepath.
    
    // Get start & end positions
    number = bracketOpen + 1;
    while(*number == ' ') number++; // skip over whitespace
    if(*number != ':')
    {
        *start = strtol(number, 0, 0);
    }
    number = colon + 1;
    while(*number == ' ') number++; // skip over whitespace
    if(*number != ']')
    {
        *end = strtol(number, 0, 0);
    }
}

Here are a few examples of it's usage:

char token[64] = "file.bin[16:0x1234]";
uint32_t start, end;
parse_file_range(token, &start, &end);
printf("%s, %d, %d\n", token, start, end); // Output: file.bin, 16, 4660
char token[64] = "file.bin[:0x100000]";
uint32_t start, end;
parse_file_range(token, &start, &end);
printf("%s, %d, %d\n", token, start, end); // Output: file.bin, 0, 1048576
char token[64] = "file.bin[250:]";
uint32_t start, end;
parse_file_range(token, &start, &end);
printf("%s, %d, %d\n", token, start, end); // Output: file.bin, 250, 4294967295
char token[64] = "file.bin";
uint32_t start, end;
parse_file_range(token, &start, &end);
printf("%s, %d, %d\n", token, start, end); // Output: file.bin, 0, 4294967295

Note that file.bin[:] would have the same output as file.bin.

You would need to check the bounds to the size of the file. if end is larger than the size of the file, which it is by default, then you'd need to overwrite end with the size of the file.

DavidSM64 avatar May 31 '23 20:05 DavidSM64

Sounds like a good feature to have. We'd have to think about how (or if) we should expose the file's offsets on the N64 side. Perhaps this data could be included next to the @ syntax already in use by USB reading.

buu342 avatar May 31 '23 21:05 buu342