Postscript, 23 bytes for hex input, 105 for decimal
The normal way to get a Postscript program to parse arbitrary formats is to concatenate the parser program and the input and send them to the interpreter. That's what I've done for the "no cheating" solutions.
I've set up TIO in Bash to put the program in the code section and the message in the input section. The header and footer arrange to concatenate the two and pass them to the interpreter. In the case of binary encoding, TIO's character count is wrong (it expects UTF-8 but we've got hex) so the header puts a line in the debug window with the correct count.
Hex input, no binary encoding, no cheating, 64 bytes
{currentfile 9 string readhexstring exch print not{exit} if}loop
Try it online!
There's nothing clever here. readhexstring
does the heavy lifting. The 9
is arbitrary, any size will work.
TIO counts the code as 64 bytes, but it will be mandatory to have whitespace between the program and the concatenated input string. I'm not sure if that should be counted.
If we're prepared to put a limit on the maximum size of the input message then we can make this smaller:
{currentfile 999999 string readhexstring pop print}exec
As shown, the limit could be sufficiently high that it's not a problem in practice. However, the question explicitly says no limit, so I won't persue this any further.
Hex input, binary encoding, no cheating, 23 bytes
7b 92 1f 39 92 a5 92 7c 92 3e 92 76 92 70 7b 92
40 7d 92 54 7d 92 65
Try it online!
This is a straight binary encoding of the preceding solution. Unlike the non-binary-encoded version, no whitespace is needed between the program and the input.
Hex input, no binary encoding, cheating, 7 bytes
If we're prepared to allow non-standard ways of passing the input, then we can use Postscript's hex string literals to do all the work. This involves sending character "<", then the hex coding of the input, and finally ">print". This is 7 bytes more than the original message.
<the message in hex goes here>print
Try it online!
Because the message and the program are interleaved, TIO can't count the program characters.
Hex input, binary encoding, cheating, 4 bytes
And, of course there's the binary encoded version of the cheating method where we replace print with its binary encoding \x92\x76
. This means adding just four bytes to the message being decoded.
<the message in hex goes here>\x92v
Try it online!
Note that TIO's bash input insists on UTF-8 encoding its input which mangles the \x92
into two characters so I've used iconv
in the header to undo that.
Decimal input, no binary encoding, no cheating, 202 bytes
There's a discussion in the comments about whether hex should be allowed. For Postscript, this makes a big difference.
Postscript doesn't have any big integer handling. Integer limits are implementation dependent but you can't reliably expect anything longer than 32 bits to work. For hex, the input can be processed in arbitrary chunks. For decimal, we need to convert manually. This makes it a much more interesting problem.
The best I have so far is:
[[]{{currentfile read{48 sub exch{10 mul add
dup 256 mod exch -8 bitshift}forall
dup 0 eq {pop} if][exch}{exit}ifelse}loop
dup length 1 sub -1 0{2 copy get 1 string
dup 0 4 3 roll put print pop}for}exec
Try it online!
Note that this leaves two objects on the stack. As with the earlier non-binary-encoded answer there needs to be whitespace between the program and the input.
This requires a lot more explanation:
% Our state when we're parsing the input integer is to have two elements
% on the stack, a mark (which we'll use later) and an array containing the
% integer so far in base 256, least-significant digit first.
%
% When we read a digit, we multiply the values in the array by ten modulo
% 256 overflowing into the next digit.
%
% The code won't deal with characters that aren't decimal digits, so you
% have to be very careful setting up the input to avoid whitespace creeping
% in (including a newline at the end). Adding code to deal with this adds 38
% characters to the minimised version.
[ [] % Initialise the stack with mark and zero
{ % Start of exec (so we don't start parsing till the whole
% program has been loaded)
{ % Start of the per-input-digit loop
currentfile read % Read one character from the input
{ % True path: we read a character
48 sub % Convert ASCII digit to decimal ('5' -> 5)
exch % Now have: mark new-digit array-of-current-total
{ % Start of per-existing-digit loop
% Stack: mark already-processed-digits adder next-digit
10 mul % Multiply the existing base-256 digit by ten
add % Add new input digit (first pass) or overflow
dup % Need the result twice: new digit and overflow
256 mod exch % New digit
-8 bitshift % Overflow
% Stack: mark already-processed-digits adder=overflow
} forall % End of per-existing-digit loop
dup 0 eq {pop} if % If the last overflow was zero, discard it
% We don't want lots of zeros at the top
] % Use the mark on the stack to reform the array
[ exch % Replace the mark below the array
}
{exit} ifelse % False path: end of file encountered
} loop % End of input processing
% We now have an array with the input converted to base 256
% We can't use forall on this as that would start with the
% least-significant digit and we need to start at the top. So, we'll
% use a count-down for loop to access the array elements.
dup length 1 sub -1 0
{ % Start of per-character output loop
% To convert to a character we put the digit into a 1 character string
% For the next bit, "1 index exch" is neater than "2 copy ... pop"
% but the latter is two characters shorter in non-binary encoding.
% In binary, they're the same length.
% Stack: mark base-256-array index
2 copy % Stack: mark array index array index
get % Stack: mark array index digit
1 string dup 0 % Stack: mark array index digit string string 0
4 3 roll % Stack: mark array index string string 0 digit
put % Stack: mark array index string
print % Print the converted character
pop % Lose the duplicated index
} for % End of per-character output loop
} exec
It feels like it should be possible to golf this down to something shorter.
Decimal input, binary encoding, no cheating, 105 bytes
5b 5b 5d 7b 7b 92 1f 92 7b 7b 34 38 92 a9 92 3e
7b 31 30 92 6c 92 01 92 38 32 35 36 92 6a 92 3e
2d 38 92 0f 7d 92 49 92 38 30 92 3d 7b 92 75 7d
92 54 5d 5b 92 3e 7d 7b 92 40 7d 92 55 7d 92 65
92 38 92 62 20 31 92 a9 2d 31 20 30 7b 32 92 19
92 4b 31 92 a5 92 38 30 88 04 33 92 87 92 78 92
76 92 75 7d 92 48 7d 92 3f
Try it online!
This is a straight binary encoding of the preceding solution. No whitespace is needed between the program and the input.