Fossil SCM
Fix the /file page so that it is able to play sound files that are checked into the repository. Example: [/file/src/sounds/plunk.wav]
Commit
6643d4a0c1aabb8562fc1ab1803d13fa859b2266befb73f60e82f368ea8d802c
Parent
327a82f769467b0…
2 files changed
+18
-9
+13
-6
+18
-9
| --- src/doc.c | ||
| +++ src/doc.c | ||
| @@ -38,30 +38,39 @@ | ||
| 38 | 38 | const unsigned char *x; |
| 39 | 39 | |
| 40 | 40 | /* A table of mimetypes based on file content prefixes |
| 41 | 41 | */ |
| 42 | 42 | static const struct { |
| 43 | - const char *zPrefix; /* The file prefix */ | |
| 44 | - const int size; /* Length of the prefix */ | |
| 43 | + const char *z; /* Identifying file text */ | |
| 44 | + const unsigned char sz1; /* Length of the prefix */ | |
| 45 | + const unsigned char of2; /* Offset to the second segment */ | |
| 46 | + const unsigned char sz2; /* Size of the second segment */ | |
| 47 | + const unsigned char mn; /* Minimum size of input */ | |
| 45 | 48 | const char *zMimetype; /* The corresponding mimetype */ |
| 46 | 49 | } aMime[] = { |
| 47 | - { "GIF87a", 6, "image/gif" }, | |
| 48 | - { "GIF89a", 6, "image/gif" }, | |
| 49 | - { "\211PNG\r\n\032\n", 8, "image/png" }, | |
| 50 | - { "\377\332\377", 3, "image/jpeg" }, | |
| 51 | - { "\377\330\377", 3, "image/jpeg" }, | |
| 50 | + { "GIF87a", 6, 0, 0, 6, "image/gif" }, | |
| 51 | + { "GIF89a", 6, 0, 0, 6, "image/gif" }, | |
| 52 | + { "\211PNG\r\n\032\n", 8, 0, 0, 8, "image/png" }, | |
| 53 | + { "\377\332\377", 3, 0, 0, 3, "image/jpeg" }, | |
| 54 | + { "\377\330\377", 3, 0, 0, 3, "image/jpeg" }, | |
| 55 | + { "RIFFWAVEfmt", 4, 8, 7, 15, "sound/wav" }, | |
| 52 | 56 | }; |
| 53 | 57 | |
| 54 | 58 | if( !looks_like_binary(pBlob) ) { |
| 55 | 59 | return 0; /* Plain text */ |
| 56 | 60 | } |
| 57 | 61 | x = (const unsigned char*)blob_buffer(pBlob); |
| 58 | 62 | n = blob_size(pBlob); |
| 59 | 63 | for(i=0; i<count(aMime); i++){ |
| 60 | - if( n>=aMime[i].size && memcmp(x, aMime[i].zPrefix, aMime[i].size)==0 ){ | |
| 61 | - return aMime[i].zMimetype; | |
| 64 | + if( n<aMime[i].mn ) continue; | |
| 65 | + if( memcmp(x, aMime[i].z, aMime[i].sz1)!=0 ) continue; | |
| 66 | + if( aMime[i].sz2 | |
| 67 | + && memcmp(x+aMime[i].of2, aMime[i].z+aMime[i].sz1, aMime[i].sz2)!=0 | |
| 68 | + ){ | |
| 69 | + continue; | |
| 62 | 70 | } |
| 71 | + return aMime[i].zMimetype; | |
| 63 | 72 | } |
| 64 | 73 | return "unknown/unknown"; |
| 65 | 74 | } |
| 66 | 75 | |
| 67 | 76 | /* A table of mimetypes based on file suffixes. |
| 68 | 77 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -38,30 +38,39 @@ | |
| 38 | const unsigned char *x; |
| 39 | |
| 40 | /* A table of mimetypes based on file content prefixes |
| 41 | */ |
| 42 | static const struct { |
| 43 | const char *zPrefix; /* The file prefix */ |
| 44 | const int size; /* Length of the prefix */ |
| 45 | const char *zMimetype; /* The corresponding mimetype */ |
| 46 | } aMime[] = { |
| 47 | { "GIF87a", 6, "image/gif" }, |
| 48 | { "GIF89a", 6, "image/gif" }, |
| 49 | { "\211PNG\r\n\032\n", 8, "image/png" }, |
| 50 | { "\377\332\377", 3, "image/jpeg" }, |
| 51 | { "\377\330\377", 3, "image/jpeg" }, |
| 52 | }; |
| 53 | |
| 54 | if( !looks_like_binary(pBlob) ) { |
| 55 | return 0; /* Plain text */ |
| 56 | } |
| 57 | x = (const unsigned char*)blob_buffer(pBlob); |
| 58 | n = blob_size(pBlob); |
| 59 | for(i=0; i<count(aMime); i++){ |
| 60 | if( n>=aMime[i].size && memcmp(x, aMime[i].zPrefix, aMime[i].size)==0 ){ |
| 61 | return aMime[i].zMimetype; |
| 62 | } |
| 63 | } |
| 64 | return "unknown/unknown"; |
| 65 | } |
| 66 | |
| 67 | /* A table of mimetypes based on file suffixes. |
| 68 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -38,30 +38,39 @@ | |
| 38 | const unsigned char *x; |
| 39 | |
| 40 | /* A table of mimetypes based on file content prefixes |
| 41 | */ |
| 42 | static const struct { |
| 43 | const char *z; /* Identifying file text */ |
| 44 | const unsigned char sz1; /* Length of the prefix */ |
| 45 | const unsigned char of2; /* Offset to the second segment */ |
| 46 | const unsigned char sz2; /* Size of the second segment */ |
| 47 | const unsigned char mn; /* Minimum size of input */ |
| 48 | const char *zMimetype; /* The corresponding mimetype */ |
| 49 | } aMime[] = { |
| 50 | { "GIF87a", 6, 0, 0, 6, "image/gif" }, |
| 51 | { "GIF89a", 6, 0, 0, 6, "image/gif" }, |
| 52 | { "\211PNG\r\n\032\n", 8, 0, 0, 8, "image/png" }, |
| 53 | { "\377\332\377", 3, 0, 0, 3, "image/jpeg" }, |
| 54 | { "\377\330\377", 3, 0, 0, 3, "image/jpeg" }, |
| 55 | { "RIFFWAVEfmt", 4, 8, 7, 15, "sound/wav" }, |
| 56 | }; |
| 57 | |
| 58 | if( !looks_like_binary(pBlob) ) { |
| 59 | return 0; /* Plain text */ |
| 60 | } |
| 61 | x = (const unsigned char*)blob_buffer(pBlob); |
| 62 | n = blob_size(pBlob); |
| 63 | for(i=0; i<count(aMime); i++){ |
| 64 | if( n<aMime[i].mn ) continue; |
| 65 | if( memcmp(x, aMime[i].z, aMime[i].sz1)!=0 ) continue; |
| 66 | if( aMime[i].sz2 |
| 67 | && memcmp(x+aMime[i].of2, aMime[i].z+aMime[i].sz1, aMime[i].sz2)!=0 |
| 68 | ){ |
| 69 | continue; |
| 70 | } |
| 71 | return aMime[i].zMimetype; |
| 72 | } |
| 73 | return "unknown/unknown"; |
| 74 | } |
| 75 | |
| 76 | /* A table of mimetypes based on file suffixes. |
| 77 |
+13
-6
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -2366,14 +2366,17 @@ | ||
| 2366 | 2366 | @ part of check-in %z(href("%R/info/%!S",zCIUuid))%S(zCIUuid)</a></h2> |
| 2367 | 2367 | } |
| 2368 | 2368 | blob_reset(&path); |
| 2369 | 2369 | } |
| 2370 | 2370 | style_submenu_element("Artifact", "%R/artifact/%S", zUuid); |
| 2371 | - style_submenu_element("Annotate", "%R/annotate?filename=%T&checkin=%T", | |
| 2372 | - zName, zCI); | |
| 2373 | - style_submenu_element("Blame", "%R/blame?filename=%T&checkin=%T", | |
| 2374 | - zName, zCI); | |
| 2371 | + zMime = mimetype_from_name(zName); | |
| 2372 | + if( zMime && strncmp(zMime, "text/", 5)==0 ){ | |
| 2373 | + style_submenu_element("Annotate", "%R/annotate?filename=%T&checkin=%T", | |
| 2374 | + zName, zCI); | |
| 2375 | + style_submenu_element("Blame", "%R/blame?filename=%T&checkin=%T", | |
| 2376 | + zName, zCI); | |
| 2377 | + } | |
| 2375 | 2378 | blob_init(&downloadName, zName, -1); |
| 2376 | 2379 | objType = OBJTYPE_CONTENT; |
| 2377 | 2380 | }else{ |
| 2378 | 2381 | @ <h2>Artifact |
| 2379 | 2382 | style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid); |
| @@ -2384,10 +2387,11 @@ | ||
| 2384 | 2387 | } |
| 2385 | 2388 | blob_zero(&downloadName); |
| 2386 | 2389 | if( asText ) objdescFlags &= ~OBJDESC_BASE; |
| 2387 | 2390 | objType = object_description(rid, objdescFlags, |
| 2388 | 2391 | (isFile?zName:0), &downloadName); |
| 2392 | + zMime = mimetype_from_name(blob_str(&downloadName)); | |
| 2389 | 2393 | } |
| 2390 | 2394 | if( !descOnly && P("download")!=0 ){ |
| 2391 | 2395 | cgi_redirectf("%R/raw/%s?at=%T", |
| 2392 | 2396 | db_text("x", "SELECT uuid FROM blob WHERE rid=%d", rid), |
| 2393 | 2397 | file_tail(blob_str(&downloadName))); |
| @@ -2439,11 +2443,10 @@ | ||
| 2439 | 2443 | } |
| 2440 | 2444 | style_submenu_element("Download", "%R/raw/%s?at=%T", zUuid, file_tail(zName)); |
| 2441 | 2445 | if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){ |
| 2442 | 2446 | style_submenu_element("Check-ins Using", "%R/timeline?uf=%s", zUuid); |
| 2443 | 2447 | } |
| 2444 | - zMime = mimetype_from_name(blob_str(&downloadName)); | |
| 2445 | 2448 | if( zMime ){ |
| 2446 | 2449 | if( fossil_strcmp(zMime, "text/html")==0 ){ |
| 2447 | 2450 | if( asText ){ |
| 2448 | 2451 | style_submenu_element("Html", "%s", url_render(&url, "txt", 0, 0, 0)); |
| 2449 | 2452 | }else{ |
| @@ -2504,11 +2507,11 @@ | ||
| 2504 | 2507 | style_submenu_element("Hex", "%R/hexdump?name=%s", zUuid); |
| 2505 | 2508 | if( zLn==0 || atoi(zLn)==0 ){ |
| 2506 | 2509 | style_submenu_checkbox("ln", "Line Numbers", 0, 0); |
| 2507 | 2510 | } |
| 2508 | 2511 | blob_to_utf8_no_bom(&content, 0); |
| 2509 | - zMime = mimetype_from_content(&content); | |
| 2512 | + if( zMime==0 ) zMime = mimetype_from_content(&content); | |
| 2510 | 2513 | @ <blockquote class="file-content"> |
| 2511 | 2514 | if( zMime==0 ){ |
| 2512 | 2515 | const char *z, *zFileName, *zExt; |
| 2513 | 2516 | z = blob_str(&content); |
| 2514 | 2517 | zFileName = db_text(0, |
| @@ -2531,10 +2534,14 @@ | ||
| 2531 | 2534 | } |
| 2532 | 2535 | }else if( strncmp(zMime, "image/", 6)==0 ){ |
| 2533 | 2536 | @ <p>(file is %d(blob_size(&content)) bytes of image data)</i></p> |
| 2534 | 2537 | @ <p><img src="%R/raw/%s(zUuid)?m=%s(zMime)"></p> |
| 2535 | 2538 | style_submenu_element("Image", "%R/raw/%s?m=%s", zUuid, zMime); |
| 2539 | + }else if( strncmp(zMime, "audio/", 6)==0 ){ | |
| 2540 | + @ <audio controls src="%R/raw/%s(zUuid)?m=%s(zMime)"> | |
| 2541 | + @ (Not supported by this browser) | |
| 2542 | + @ </audio> | |
| 2536 | 2543 | }else{ |
| 2537 | 2544 | @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i> |
| 2538 | 2545 | } |
| 2539 | 2546 | @ </blockquote> |
| 2540 | 2547 | } |
| 2541 | 2548 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -2366,14 +2366,17 @@ | |
| 2366 | @ part of check-in %z(href("%R/info/%!S",zCIUuid))%S(zCIUuid)</a></h2> |
| 2367 | } |
| 2368 | blob_reset(&path); |
| 2369 | } |
| 2370 | style_submenu_element("Artifact", "%R/artifact/%S", zUuid); |
| 2371 | style_submenu_element("Annotate", "%R/annotate?filename=%T&checkin=%T", |
| 2372 | zName, zCI); |
| 2373 | style_submenu_element("Blame", "%R/blame?filename=%T&checkin=%T", |
| 2374 | zName, zCI); |
| 2375 | blob_init(&downloadName, zName, -1); |
| 2376 | objType = OBJTYPE_CONTENT; |
| 2377 | }else{ |
| 2378 | @ <h2>Artifact |
| 2379 | style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid); |
| @@ -2384,10 +2387,11 @@ | |
| 2384 | } |
| 2385 | blob_zero(&downloadName); |
| 2386 | if( asText ) objdescFlags &= ~OBJDESC_BASE; |
| 2387 | objType = object_description(rid, objdescFlags, |
| 2388 | (isFile?zName:0), &downloadName); |
| 2389 | } |
| 2390 | if( !descOnly && P("download")!=0 ){ |
| 2391 | cgi_redirectf("%R/raw/%s?at=%T", |
| 2392 | db_text("x", "SELECT uuid FROM blob WHERE rid=%d", rid), |
| 2393 | file_tail(blob_str(&downloadName))); |
| @@ -2439,11 +2443,10 @@ | |
| 2439 | } |
| 2440 | style_submenu_element("Download", "%R/raw/%s?at=%T", zUuid, file_tail(zName)); |
| 2441 | if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){ |
| 2442 | style_submenu_element("Check-ins Using", "%R/timeline?uf=%s", zUuid); |
| 2443 | } |
| 2444 | zMime = mimetype_from_name(blob_str(&downloadName)); |
| 2445 | if( zMime ){ |
| 2446 | if( fossil_strcmp(zMime, "text/html")==0 ){ |
| 2447 | if( asText ){ |
| 2448 | style_submenu_element("Html", "%s", url_render(&url, "txt", 0, 0, 0)); |
| 2449 | }else{ |
| @@ -2504,11 +2507,11 @@ | |
| 2504 | style_submenu_element("Hex", "%R/hexdump?name=%s", zUuid); |
| 2505 | if( zLn==0 || atoi(zLn)==0 ){ |
| 2506 | style_submenu_checkbox("ln", "Line Numbers", 0, 0); |
| 2507 | } |
| 2508 | blob_to_utf8_no_bom(&content, 0); |
| 2509 | zMime = mimetype_from_content(&content); |
| 2510 | @ <blockquote class="file-content"> |
| 2511 | if( zMime==0 ){ |
| 2512 | const char *z, *zFileName, *zExt; |
| 2513 | z = blob_str(&content); |
| 2514 | zFileName = db_text(0, |
| @@ -2531,10 +2534,14 @@ | |
| 2531 | } |
| 2532 | }else if( strncmp(zMime, "image/", 6)==0 ){ |
| 2533 | @ <p>(file is %d(blob_size(&content)) bytes of image data)</i></p> |
| 2534 | @ <p><img src="%R/raw/%s(zUuid)?m=%s(zMime)"></p> |
| 2535 | style_submenu_element("Image", "%R/raw/%s?m=%s", zUuid, zMime); |
| 2536 | }else{ |
| 2537 | @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i> |
| 2538 | } |
| 2539 | @ </blockquote> |
| 2540 | } |
| 2541 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -2366,14 +2366,17 @@ | |
| 2366 | @ part of check-in %z(href("%R/info/%!S",zCIUuid))%S(zCIUuid)</a></h2> |
| 2367 | } |
| 2368 | blob_reset(&path); |
| 2369 | } |
| 2370 | style_submenu_element("Artifact", "%R/artifact/%S", zUuid); |
| 2371 | zMime = mimetype_from_name(zName); |
| 2372 | if( zMime && strncmp(zMime, "text/", 5)==0 ){ |
| 2373 | style_submenu_element("Annotate", "%R/annotate?filename=%T&checkin=%T", |
| 2374 | zName, zCI); |
| 2375 | style_submenu_element("Blame", "%R/blame?filename=%T&checkin=%T", |
| 2376 | zName, zCI); |
| 2377 | } |
| 2378 | blob_init(&downloadName, zName, -1); |
| 2379 | objType = OBJTYPE_CONTENT; |
| 2380 | }else{ |
| 2381 | @ <h2>Artifact |
| 2382 | style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid); |
| @@ -2384,10 +2387,11 @@ | |
| 2387 | } |
| 2388 | blob_zero(&downloadName); |
| 2389 | if( asText ) objdescFlags &= ~OBJDESC_BASE; |
| 2390 | objType = object_description(rid, objdescFlags, |
| 2391 | (isFile?zName:0), &downloadName); |
| 2392 | zMime = mimetype_from_name(blob_str(&downloadName)); |
| 2393 | } |
| 2394 | if( !descOnly && P("download")!=0 ){ |
| 2395 | cgi_redirectf("%R/raw/%s?at=%T", |
| 2396 | db_text("x", "SELECT uuid FROM blob WHERE rid=%d", rid), |
| 2397 | file_tail(blob_str(&downloadName))); |
| @@ -2439,11 +2443,10 @@ | |
| 2443 | } |
| 2444 | style_submenu_element("Download", "%R/raw/%s?at=%T", zUuid, file_tail(zName)); |
| 2445 | if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){ |
| 2446 | style_submenu_element("Check-ins Using", "%R/timeline?uf=%s", zUuid); |
| 2447 | } |
| 2448 | if( zMime ){ |
| 2449 | if( fossil_strcmp(zMime, "text/html")==0 ){ |
| 2450 | if( asText ){ |
| 2451 | style_submenu_element("Html", "%s", url_render(&url, "txt", 0, 0, 0)); |
| 2452 | }else{ |
| @@ -2504,11 +2507,11 @@ | |
| 2507 | style_submenu_element("Hex", "%R/hexdump?name=%s", zUuid); |
| 2508 | if( zLn==0 || atoi(zLn)==0 ){ |
| 2509 | style_submenu_checkbox("ln", "Line Numbers", 0, 0); |
| 2510 | } |
| 2511 | blob_to_utf8_no_bom(&content, 0); |
| 2512 | if( zMime==0 ) zMime = mimetype_from_content(&content); |
| 2513 | @ <blockquote class="file-content"> |
| 2514 | if( zMime==0 ){ |
| 2515 | const char *z, *zFileName, *zExt; |
| 2516 | z = blob_str(&content); |
| 2517 | zFileName = db_text(0, |
| @@ -2531,10 +2534,14 @@ | |
| 2534 | } |
| 2535 | }else if( strncmp(zMime, "image/", 6)==0 ){ |
| 2536 | @ <p>(file is %d(blob_size(&content)) bytes of image data)</i></p> |
| 2537 | @ <p><img src="%R/raw/%s(zUuid)?m=%s(zMime)"></p> |
| 2538 | style_submenu_element("Image", "%R/raw/%s?m=%s", zUuid, zMime); |
| 2539 | }else if( strncmp(zMime, "audio/", 6)==0 ){ |
| 2540 | @ <audio controls src="%R/raw/%s(zUuid)?m=%s(zMime)"> |
| 2541 | @ (Not supported by this browser) |
| 2542 | @ </audio> |
| 2543 | }else{ |
| 2544 | @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i> |
| 2545 | } |
| 2546 | @ </blockquote> |
| 2547 | } |
| 2548 |