7
\$\begingroup\$

In case https://tio.run - a popular online interpreter developed and managed by @DennisMitchell - were to shut down, we need to be able to decode the url.

Task

Given an URL, decode and extract the source of the Code. No need to extract Header and Footer and every other elements. The URL shall begin with https://tio.run/##.

Test cases

/// https://codegolf.stackexchange.com/a/89/113493
https://tio.run/##y0gszk7Nyfn/P83W0Ko4OTEvR0Nb0zDtf25iZp6CrUJBUWZeiYJGSWJ2qoKhgYGCikKa5n8A
=> f=1:scanl(+)1f

/// https://codegolf.stackexchange.com/a/11000/113493
https://tio.run/##FcnBDkAwDADQX5GdLE3F0TazP5GIIG3FRMXvD@/6eHomnS86b3y6UtZ81RRdQCRwYc6H5n1p9rzVau2f/CUHjYw4uiRDmwQUxJvKgHoBY6xE6tvEQJ6RSnkB
=> for(i=9;--i+9;console.log(s))for(j=9;j;s=j--^9?k>0?k+s+k:" "+s:k+"")k=i<0?j+i:j-i

/// https://codegolf.stackexchange.com/a/194502/113493
https://tio.run/##S83Nz8r8///R7L2pmekZJR/mz5rxaN7C//8B
=> ⛽eight🚘➡

/// https://codegolf.stackexchange.com/a/272496/113493
https://tio.run/##MzBNTDJM/V9Waa@k8KhtkoKSfWVC8f/SRw2zzm171LTm8IKc/146/6OjlRL1gCBJSUdJTy8ZyFKK1YGKIQSxiYEBTAIiqpcM4YMBUCQJDCBiSXpABBLTA0EkAyGagTpjAQ
=> u‚ζ€àl

https://tio.run/##y0hJSvufnJ@S@j89PydN739xRn5RSWpxCUSsPDOvWO9ffkFJZn5e8f@QjMzi/5nFAA
=> golf.

Longer test cases

How decoding works: walkthrough.

: See also frontend.js on GitHub repository.

Take the following test case as example:

https://tio.run/##MzBNTDJM/V9Waa@k8KhtkoKSfWVC8f/SRw2zzm171LTm8IKc/146/6OjlRL1gCBJSUdJTy8ZyFKK1YGKIQSxiYEBTAIiqpcM4YMBUCQJDCBiSXpABBLTA0EkAyGagTpjAQ

Extract the substring following two hashes:

MzBNTDJM/V9Waa@k8KhtkoKSfWVC8f/SRw2zzm171LTm8IKc/146/6OjlRL1gCBJSUdJTy8ZyFKK1YGKIQSxiYEBTAIiqpcM4YMBUCQJDCBiSXpABBLTA0EkAyGagTpjAQ

Replace every atmark with plus sign and decode as base64:

$ echo ... | tr @ + | base64 -d | od -A x -t x1
000000 33 30 4d 4c 32 4c fd 5f 56 69 af a4 f0 a8 6d 92
000010 82 92 7d 65 42 f1 ff d2 47 0d b3 ce 6d 7b d4 b4
000020 e6 f0 82 9c ff 5e 3a ff a3 a3 95 12 f5 80 20 49
000030 49 47 49 4f 2f 19 c8 52 8a d5 81 8a 21 04 b1 89
000040 81 01 4c 02 22 aa 97 0c e1 83 01 50 24 09 0c 20
000050 62 49 7a 40 04 12 d3 03 41 24 03 21 9a 81 3a 63
000060 01
000061

The binary represents compressed data in manner of RFC 1951; uncompress it:

$ ... | perl -MIO::Uncompress::RawInflate=rawinflate -erawinflate\ qw/-\ -/|od -Ax -tc
   0   5   a   b   1   e 377   v   y   ?   "     342 206 222    
   "   ?   y   `   s 377   u 342 200 232 316 266 342 202 254 303
 240   l 377   J   , 377   [   [   "   a   .   .   .   .   b   "
   ,   "   .   .   c   .   .   .   "   ]   ,   [   "   a   .   .
   .   .   .   b   "   ,   "   .   .   c   .   .   "   ]   ,   [
   "   a   .   .   .   .   .   b   "   ,   "   .   .   c   .   .
   .   .   .   .   .   "   ]   ,   [   "   a   .   .   b   "   ,
   "   .   .   .   c   "   ]   ,   [   "   a   a   a   a   a   a
   "   ,   "   b   b   b   b   b   b   "   ]   ,   [   "   a   b
   .   a   b   .   "   ,   "   b   .   b   .   b   .   "   ]   ,
   [   "   a   .   .   .   .   .   .   .   b   "   ,   "   c   "
   ]   ]

If a byte of 0xf3, 0xf4, ..., or 0xfe occurs within the data, remove it and rest. Since this example doesn't have any of them, nothing changes.

Separate each part with 0xff and take third field out of them; this is the result.

u‚ζ€àl

Incomplete reference implementation in Bash because it somehow outputs input for case of V (vim) answer to implement Whitespace, 473 bytes

cut -d# -f3-|tr @ +|base64 -d|perl -MIO::Uncompress::RawInflate=rawinflate -erawinflate\ qw/-\ -/|cut -d "$(printf \\xf3)" -f1|cut -d "$(printf \\xf4)" -f1|cut -d "$(printf \\xf5)" -f1|cut -d "$(printf \\xf6)" -f1|cut -d "$(printf \\xf7)" -f1|cut -d "$(printf \\xf8)" -f1|cut -d "$(printf \\xf9)" -f1|cut -d "$(printf \\xfa)" -f1|cut -d "$(printf \\xfb)" -f1|cut -d "$(printf \\xfc)" -f1|cut -d "$(printf \\xfd)" -f1|cut -d "$(printf \\xfe)" -f1|cut -d"$(printf \\xff)" -f3

Try it online!

Rules

Standard I/O. Standard loopholes. Code-golf.

\$\endgroup\$
6
  • \$\begingroup\$ sandbox \$\endgroup\$ Commented Apr 11 at 13:46
  • \$\begingroup\$ So 0xf3 is treated as end of input? \$\endgroup\$ Commented Apr 11 at 16:44
  • \$\begingroup\$ have tried "incomplete" implement with short urls and seems working \$\endgroup\$ Commented Apr 11 at 22:50
  • 2
    \$\begingroup\$ Note that 0xF5 through 0xFF can never appear in a valid UTF-8 string, so they would presumably not appear in the input at all (except when used as separators). However, I’m not sure why 0xF3 and 0xF4 should be treated specially. \$\endgroup\$ Commented Apr 13 at 8:31
  • 3
    \$\begingroup\$ since it seems you're unaware: Dennis Mitchell is our very own Dennis \$\endgroup\$ Commented Apr 13 at 9:03

3 Answers 3

5
\$\begingroup\$

JavaScript (Node.js), 126 bytes

x=>B(require('zlib').inflateRawSync(B(x.slice(18).split`@`.join`+`,'base64')).toString(b=`binary`).split`ÿ`[2],b)+''
B=Buffer

Try it online!

\xF3 thing unclearly described, thus not handled.

\$\endgroup\$
2
\$\begingroup\$

Python 3, 135 bytes

lambda s:zlib.decompress(base64.b64decode(s[18:].translate({64:43})+~-~len(s)%4*"="),-15).split(b'\xff')[2].decode()
import base64,zlib

Try it online! Link includes test cases. Does not try to handle the \xf3..\xfe bytes.

\$\endgroup\$
1
\$\begingroup\$

Rust, 149 bytes

|l:&str|String::from_utf8(inflate::inflate_bytes(&base64_light::base64_decode(&l[18..].replace('@',"+"))).ok()?.split(|b|*b>245).nth(2)?.into()).ok()

Returns an Option<String>, as per this meta
Uses two external crates (ecosystem name for libraries), as per this enumeration of allowed/disallowed imports the amount of characters needed to use them is counted to the score. Required links:

Rust playground link

Ungolfed and explained:

// imports, but these can also be directly accessed as module paths
// if the corresponding crates are listed as deps in Cargo.toml
use inflate::inflate_bytes;
// I chose this lib because it doesn't throw padding errors for its default behavior
use base64_light::base64_decode;

/// Decoding function, takes the typical reference string type and returns
/// a result with an owned string or an error
fn decode(link :&str) -> Option<String> {
  let code = link[18..] // substring from the 18th byte, strips https://tio.run/##
             .replace('@',"+"); // replace @ with #, get back an owned String
  let decoded = base64_decode(&code); // decode to a Vec of bytes
  let inflated = inflate_bytes(&decoded) // inflate the bytes
                 .ok() // conversion of Result<T,E> into Option<T>
                 ?; // unwrap the option or early return if None
  let code_segment = inflated // Split is an iterator over slices (&[u8)
                     .split(|b|*b>245) // split on bytes >245 (invalid UTF-8)
                     .nth(2) // ignore language and header
                     ? // Iterators return Options, None means they're exhausted
                     .into() // convert it into an owned Vec
  // Rust does implicit return on the last statement if it has no semicolon
  String::from_utf8(code_segment) // Error if the string is not valid UTF-8
  .ok() // convert to an option again
}
```
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.