aboutsummaryrefslogtreecommitdiff
path: root/arm9/source/types/pathbuf.c
blob: e94b955b9bf2cbb13a879f339dd5ddaddcb7f6a3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include "pathbuf.h"


// Read the next byte of the path buffer, or zero if all bytes have been read.
u8 pathbuf_read(PathBuf *buf) {
    u8 output = buf->mem[buf->p];
    if (output) buf->p++;
    return output;
}

// Clear a path buffer.
void pathbuf_clear(PathBuf *buf) {
    for (int i=0; i<256; i++) buf->mem[i] = 0;
    buf->p = 0;
}

// Move the pointer to either the start of the path buffer or to the start of
// the final path component.
void pathbuf_set_pointer(PathBuf *buf, bool to_final_component) {
    buf->p = 0;
    if (to_final_component) {
        for (int i=0; i<255; i++) {
            if (buf->mem[i] == '/') {
                buf->p = i+1;
            } else if (buf->mem[i] == 0) {
                break;
            }
        }
    }
}

// Populate a path buffer with a bytestring.
void pathbuf_populate(PathBuf *buf, u8 *path) {
    pathbuf_clear(buf);
    u8 c;
    for (int i=0; i<256; i++) {
        c = path[i];
        buf->mem[i] = c;
        if (c == 0) return;
    };
}

// Push a byte to a path buffer, return true and reset pointer if byte is null.
bool pathbuf_push(PathBuf *buf, u8 byte) {
    buf->mem[buf->p++] = byte;
    return byte == 0;
}

// Check if a path buffer is empty.
bool pathbuf_is_empty(PathBuf *buf) {
    return buf->mem[0] == 0;
}

// Check if a path buffer contains the path of the root directory.
bool pathbuf_is_root(PathBuf *buf) {
    return buf->mem[0] == '/' && buf->mem[1] == 0;
}

// Check if a path buffer contains a valid path.
bool pathbuf_is_valid(PathBuf *buf) {
    // Test that path begins with a forward slash and ends with a null byte.
    if (buf->mem[0x00] != '/') return false;
    if (buf->mem[0xFF] !=  0 ) return false;
    // Find the length of the path.
    int len = 0;
    for (; len<256; len++) if (buf->mem[len] == 0) break;
    // End early if path is the root directory.
    if (len == 1) return true;
    // Test that path contains no control characters.
    for (int i=0; i<len; i++) if (buf->mem[i] < 0x20) return false;
    // Test that path contains no empty or relative components. This also
    // happens to test that it doesn't end with a slash.
    bool is_empty = false;
    bool all_dots = false;
    int dot_count = 0;
    u8 c;
    for (int i=0; i<=len; i++) {
        c = buf->mem[i];
        if (c == '/' || c == 0) {
            // Test if component is empty.
            if (is_empty) return false;
            // Test if component is one or two periods.
            if (all_dots && dot_count < 3) return false;
            // Reset flags.
            is_empty = true;
            all_dots = true;
            dot_count = 0;
        } else {
            is_empty = false;
            if (c == '.') {
                dot_count++;
            } else {
                all_dots = false;
            }
        }
    }
    return true;
}