-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathhugo.c
139 lines (115 loc) · 3.82 KB
/
hugo.c
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* hugo.c Treaty of Babel module for hugo files
* 2006 By L. Ross Raszewski
*
* This file depends on treaty_builder.h
*
* This file is public domain, but note that any changes to this file
* may render it noncompliant with the Treaty of Babel
*/
#define FORMAT hugo
#define HOME_PAGE "http://www.generalcoffee.com"
#define FORMAT_EXT ".hex"
#define NO_METADATA
#define NO_COVER
#include "treaty_builder.h"
#include <ctype.h>
#include <stdio.h>
static int number_of_hexadecimals_before_hyphen(char *s, size_t len)
{
size_t offset = 0;
while (offset < len && isxdigit(s[offset]))
offset++;
if (offset == len || (offset < len && s[offset] == '-'))
return offset;
return 0;
}
/* We look for the pattern XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX (8-4-4-4-12)
* where X is a number or A-F.
* One Hugo game, PAXLess, uses lowercase letters. The rest all use uppercase.
*/
static int isUUID(char *s)
{
if (!(number_of_hexadecimals_before_hyphen(s, 9) == 8))
return 0;
if (!(number_of_hexadecimals_before_hyphen(s+9, 5) == 4))
return 0;
if (!(number_of_hexadecimals_before_hyphen(s+14, 5) == 4))
return 0;
if (!(number_of_hexadecimals_before_hyphen(s+19, 5) == 4))
return 0;
if (!(number_of_hexadecimals_before_hyphen(s+24, 12) == 12))
return 0;
return 1;
}
/* The Hugo text obfuscation adds 20 to every character */
static char hugo_decode(char c)
{
int decoded_char = c - 20;
if (decoded_char < 0)
decoded_char = decoded_char + 256;
return (char)decoded_char;
}
static int32 get_story_file_IFID(void *s_file, int32 extent, char *output, int32 output_extent)
{
size_t i,j;
char ser[9];
char buffer[32];
char UUID_candidate[37];
char hyphen = '-'+20;
char *story_file = (char *) s_file;
if (extent<0x0B) return INVALID_STORY_FILE_RV;
for(i=0;i<extent-28;i++)
{
/* First we look for an obfuscated hyphen, '-' + 20 */
/* We need to look 8 characters behind and 28 ahead */
if (story_file[i] == hyphen && i >= 8 && extent-i >= 28 &&
story_file[i+5] == hyphen &&
story_file[i+10] == hyphen &&
story_file[i+15] == hyphen)
{
for (j=0;j<36;j++)
{
UUID_candidate[j] = hugo_decode(story_file[i+j-8]);
}
if (isUUID(UUID_candidate))
{
/* Found valid UUID at file offset i - 8 */
ASSERT_OUTPUT_SIZE((signed) 37);
memcpy(output,UUID_candidate,36);
output[36]='\0';
return 1;
}
}
}
/* Found no UUID in file. Construct legacy IFID */
memcpy(ser, (char *) story_file+0x03, 8);
ser[8]=0;
for(j=0;j<8;j++)
if (!isalnum(ser[j])) ser[j]='-';
sprintf(buffer,"HUGO-%d-%02X-%02X-%s",story_file[0],story_file[1], story_file[2],ser);
ASSERT_OUTPUT_SIZE((signed) strlen(buffer)+1);
strcpy((char *)output,buffer);
return 1;
}
static uint32 read_hugo_addx(unsigned char *from)
{
return ((uint32) from[0])| ((uint32)from[1] << 8);
}
static int32 claim_story_file(void *story_file, int32 exten)
{
unsigned char *sf=(unsigned char *)story_file;
int32 i;
int32 scale;
uint32 extent=(uint32) exten;
if (!story_file || extent < 0x28) return INVALID_STORY_FILE_RV;
/* 39 is the largest version currently accepted by the Hugo interpreter:
https://github.com/garglk/garglk/blob/master/terps/hugo/source/hemisc.c#L1310-L1362
*/
if (sf[0] > 39) return INVALID_STORY_FILE_RV;
if (sf[0]<34) scale=4;
else scale=16;
for(i=3;i<0x0B;i++) if (sf[i]<0x20 || sf[i]>0x7e) return INVALID_STORY_FILE_RV;
for(i=0x0b;i<0x18;i+=2)
if (read_hugo_addx(sf+i) * scale > extent) return INVALID_STORY_FILE_RV;
return VALID_STORY_FILE_RV;
}