├── .gitignore ├── LICENSE ├── README.md ├── disks ├── DeluxePaintIII.adf ├── VogueMusicDisk.adf └── spudmine7.adf ├── img └── amiga.svg ├── index.html ├── script ├── adf.js ├── file.js ├── filehandlers │ ├── amos.js │ ├── detect.js │ ├── dms.js │ ├── icon.js │ ├── iff.js │ └── mod.js ├── lib │ ├── filesaver.js │ └── zlib.js └── main.js ├── style └── main.css └── tosec ├── amiga.png ├── index.html ├── script ├── main.js └── md5.js └── style └── main.css /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff: 7 | .idea/workspace.xml 8 | .idea/tasks.xml 9 | 10 | # Sensitive or high-churn files: 11 | .idea/dataSources/ 12 | .idea/dataSources.ids 13 | .idea/dataSources.xml 14 | .idea/dataSources.local.xml 15 | .idea/sqlDataSources.xml 16 | .idea/dynamic.xml 17 | .idea/uiDesigner.xml 18 | 19 | # Gradle: 20 | .idea/gradle.xml 21 | .idea/libraries 22 | 23 | # Mongo Explorer plugin: 24 | .idea/mongoSettings.xml 25 | 26 | ## File-based project format: 27 | *.iws 28 | 29 | ## Plugin-specific files: 30 | 31 | # IntelliJ 32 | /out/ 33 | 34 | # mpeltonen/sbt-idea plugin 35 | .idea_modules/ 36 | 37 | # JIRA plugin 38 | atlassian-ide-plugin.xml 39 | 40 | # Crashlytics plugin (for Android Studio and IntelliJ) 41 | com_crashlytics_export_strings.xml 42 | crashlytics.properties 43 | crashlytics-build.properties 44 | fabric.properties 45 | 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Steffest 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ADF reader/writer 2 | This is an implementation of the Amiga Filesystem in plain javascript. 3 | It can be used to read, extract and write files from/to Amiga Disk Format (*.adf and *.hdf) files. 4 | 5 | 6 | Both Original (OFS) and Fast File System (FFS) are supported in both ADF floppy disk images and HDF hard disk images. 7 | Hard disk images with multiple partitions are not supported yet. 8 | 9 | The main module is [adf.js](https://github.com/steffest/ADF-reader/blob/master/script/adf.js) 10 | It uses a binary file wrapper at [file.js](https://github.com/steffest/ADF-reader/blob/master/script/file.js) for easy parsing binary data. 11 | 12 | The rest of the package is a small demo, providing a simple user interface to 13 | - browse the disk 14 | - extract/view files 15 | - create folders and files 16 | Live demo at [http://www.stef.be/adfviewer/](http://www.stef.be/adfviewer/) 17 | 18 | It can disregard all block checksums and file attributes, which makes it quite useful to salvage files from corrupt disks. 19 | For further digging, you can also extract raw sectors for reconstructing deleted files etc. 20 | 21 | I mainly wrote it to quickly inspect .adf files for Amiga music tracker files or [Emerald Mine disks](http://www.emeraldmines.net/) without the need to fire up an Amiga Emulator. 22 | Basic writing support was added for interaction with the [Scripted Amiga Emulator](https://github.com/naTmeg/ScriptedAmigaEmulator) 23 | 24 | ### Main API: 25 | 26 | #### adf.loadDisk(source) 27 | > Loads a disk from an adf or hdf file. When source is a string, it's considered as a URI, otherwise you can pass an ArrayBuffer. 28 | > All future actions will be done on this disk. 29 | 30 | #### adf.getInfo() 31 | > Returns some basic info on the disk. 32 | 33 | #### adf.getFreeSize() 34 | > Returns the used and free space of the disk (in blocks and bytes). 35 | 36 | #### adf.readRootFolder() 37 | > Returns the files and directories of the root folder of the disk. 38 | > Each file and folder has a *sector* parameters which points to the start sector of the file or folder. 39 | 40 | #### adf.readFolderAtSector(sector) 41 | > Returns the files and directories of a specific folder that starts at *sector*. 42 | > The starting sector is usually obtained from listing the root folder. 43 | > Each file and folder has a *sector* parameters which points to the start sector of the file or folder. 44 | > Each file and folder also has a *parent* parameter indicating the parent folder so you can traverse back up. 45 | 46 | #### adf.readFileAtSector(sector,includeContent) 47 | > Returns the file info (and optional content) of the file starting at *sector* 48 | > The starting sector is usually obtained from listing a folder. 49 | > If *includeContent* is true then the *content* parameter contains the binary content of the file. 50 | 51 | #### adf.writeFile(name,buffer,folderSector) 52 | > Creates a new file into a specific folder. 53 | > It returns the sector of the new file on succes or *False* on failure. (e.g. because diskspace is insufficient) 54 | > Buffer is an ArrayBuffer with the binary content 55 | > Sequential datablocks are used as much as possible to speed up reading on an actual (or emulated) Amiga." 56 | 57 | #### adf.deleteFileAtSector(sector) 58 | > Deletes a file 59 | > Just as on the Amiga only the entry of the file in its folder is removed, all the header and datablocks are left intact, 60 | > so it's possible to reconstruct the file as long as no new data is written to the disk. 61 | 62 | #### adf.createFolder(name,folderSector) 63 | > Creates a folder. 64 | > it returns the sector of the new folder 65 | 66 | #### adf.deleteFolderAtSector(sector) 67 | > Deletes a folder 68 | > Please note that the folder must me empty so for recursive deletion you should first list the folder, 69 | > then delete all files and finally delete the folder 70 | 71 | #### adf.renameFileOrFolderAtSector(sector,newname) 72 | > Renames a file or a folder. 73 | > the maximum length of a name is 30 chars. 74 | > the characters / and : are not allowed 75 | 76 | 77 | ### additional API 78 | The following methods are available for low level disk reading 79 | 80 | #### readSector(sector) 81 | > Returns a raw sector from the disk. 82 | > A sector of a standard Amiga is 512 bytes 83 | 84 | #### getSectorType(sector) 85 | > Returns the type of the sector (headerBlock, dataBlock, extentionBlock, ...) 86 | 87 | #### readHeaderBlock(sector) 88 | > Returns a parsed headerBlock 89 | 90 | #### readDataBlock(sector) 91 | > Returns a parsed dataBlock 92 | 93 | #### readExtensionBlock(sector) 94 | > Returns a parsed extentionBlock 95 | 96 | #### readBitmapblock(sector) 97 | > Returns a parsed bitmapBlock 98 | 99 | #### readBitmapExtensionBlock(sector) 100 | > Returns a parsed extended bitmapBlock 101 | 102 | #### getDisk() 103 | > Returns the current disk structure. the "buffer" property contains the binary data of the disk 104 | 105 | ### Notes 106 | **Writing support is still a bit experimental**. 107 | Don't use it for important stuff, it certainly is **not** production ready. 108 | When writing, all dates are ignore for the time being, so "last changed" and "last accessed" dates will not be updated. 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /disks/DeluxePaintIII.adf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steffest/ADF-reader-writer/f60b0167bc5a99fbc71cef387f811135cf9aec58/disks/DeluxePaintIII.adf -------------------------------------------------------------------------------- /disks/VogueMusicDisk.adf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steffest/ADF-reader-writer/f60b0167bc5a99fbc71cef387f811135cf9aec58/disks/VogueMusicDisk.adf -------------------------------------------------------------------------------- /disks/spudmine7.adf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steffest/ADF-reader-writer/f60b0167bc5a99fbc71cef387f811135cf9aec58/disks/spudmine7.adf -------------------------------------------------------------------------------- /img/amiga.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 22 | 24 | 28 | 32 | 36 | 37 | 39 | 43 | 47 | 51 | 55 | 59 | 60 | 62 | 66 | 70 | 71 | 73 | 77 | 81 | 85 | 89 | 90 | 100 | 110 | 120 | 130 | 140 | 150 | 160 | 170 | 180 | 190 | 200 | 210 | 220 | 230 | 240 | 250 | 251 | 267 | 269 | 270 | 272 | image/svg+xml 273 | 275 | 276 | 277 | 278 | 282 | 285 | 293 | 301 | 309 | 317 | 318 | 319 | 320 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 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 | or choose a test disk: 27 | 37 |
38 | Drop your .adf or *.hdf files here 39 |
40 | 41 |
42 |
43 | 44 |
45 |
46 |
47 |

Title

48 |
49 |
50 |
51 | 52 |
53 |
54 |
55 |
OK
56 |
Cancel
57 |
58 |
59 |
60 |
ADF file
61 |
62 |
63 |
Read Raw sectors
64 |
Disk:
65 |
 
66 |
67 |
68 | 69 |
70 |
71 | 72 |
73 |
74 |
75 | 76 |
77 |
78 |
Back
79 |
File:
80 |
 
81 |
82 | 85 | 88 | 89 | 90 |
91 |
92 | 93 | 94 | 95 |
96 |
97 |
Back
98 | Sector: 99 |
-
100 | 101 |
>
102 | 103 |
104 | 107 | 110 |
111 |
112 | 113 |
114 | 115 | 116 | 117 | 118 | 119 |
120 | 121 | 122 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /script/file.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | MIT License 4 | 5 | Copyright (c) 2019 Steffest - dev@stef.be 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | 25 | */ 26 | 27 | function BinaryStream(arrayBuffer, bigEndian){ 28 | var obj = { 29 | index: 0, 30 | litteEndian : !bigEndian 31 | }; 32 | 33 | obj.goto = function(value){ 34 | setIndex(value); 35 | }; 36 | 37 | obj.jump = function(value){ 38 | this.goto(this.index + value); 39 | }; 40 | 41 | obj.readByte = function(position){ 42 | setIndex(position); 43 | var b = this.dataView.getInt8(this.index); 44 | this.index++; 45 | return b; 46 | }; 47 | 48 | obj.writeByte = function(value,position){ 49 | setIndex(position); 50 | this.dataView.setInt8(this.index,value); 51 | this.index++; 52 | }; 53 | 54 | obj.readUbyte = function(position){ 55 | setIndex(position); 56 | var b = this.dataView.getUint8(this.index); 57 | this.index++; 58 | return b; 59 | }; 60 | 61 | obj.writeUbyte = function(value,position){ 62 | setIndex(position); 63 | this.dataView.setUint8(this.index,value); 64 | this.index++; 65 | }; 66 | 67 | obj.readUint = function(position){ 68 | setIndex(position); 69 | var i = this.dataView.getUint32(this.index,this.litteEndian); 70 | this.index+=4; 71 | return i; 72 | }; 73 | 74 | obj.writeUint = function(value,position){ 75 | setIndex(position); 76 | this.dataView.setUint32(this.index,value,this.litteEndian); 77 | this.index+=4; 78 | }; 79 | 80 | obj.readBytes = function(len,position,buffer) { 81 | setIndex(position); 82 | 83 | 84 | var i = this.index; 85 | var src = this.dataView; 86 | if ((len += i) > this.length) len = this.length; 87 | var offset = 0; 88 | 89 | for (; i < len; ++i) buffer.setUint8(offset++, this.dataView.getUint8(i)); 90 | this.index += len; 91 | return buffer; 92 | }; 93 | 94 | obj.readString = function(len,position){ 95 | setIndex(position); 96 | var i = this.index; 97 | var src = this.dataView; 98 | var text = ""; 99 | 100 | if ((len += i) > this.length) len = this.length; 101 | 102 | for (; i < len; ++i){ 103 | var c = src.getUint8(i); 104 | if (c == 0) break; 105 | text += String.fromCharCode(c); 106 | } 107 | 108 | this.index = len; 109 | return text; 110 | }; 111 | 112 | obj.writeString = function(value,position){ 113 | setIndex(position); 114 | var src = this.dataView; 115 | var len = value.length; 116 | for (var i = 0; i < len; i++) src.setUint8(this.index + i,value.charCodeAt(i)); 117 | this.index += len; 118 | }; 119 | 120 | obj.writeStringSection = function(value,max,paddValue,position){ 121 | setIndex(position); 122 | max = max || 1; 123 | value = value || ""; 124 | paddValue = paddValue || 0; 125 | var len = value.length; 126 | if (len>max) value = value.substr(0,max); 127 | obj.writeString(value); 128 | obj.fill(paddValue,max-len); 129 | }; 130 | 131 | // same as readUshort 132 | obj.readWord = function(position){ 133 | setIndex(position); 134 | var w = this.dataView.getUint16(this.index, this.litteEndian); 135 | this.index += 2; 136 | return w; 137 | }; 138 | 139 | obj.writeWord = function(value,position){ 140 | setIndex(position); 141 | this.dataView.setUint16(this.index,value,this.litteEndian); 142 | this.index += 2; 143 | }; 144 | 145 | obj.readLong = obj.readDWord = obj.readUint; 146 | 147 | obj.readShort = function(value,position){ 148 | setIndex(position); 149 | var w = this.dataView.getInt16(this.index, this.litteEndian); 150 | this.index += 2; 151 | return w; 152 | }; 153 | 154 | obj.readBits = function(count,bitPosition,position){ 155 | 156 | // this reads $count bits, starting from byte $position and bit position $bitPosition 157 | // bitPosition can be > 8 , count should be <= 8; 158 | 159 | position = position === 0 ? position : position || obj.index; 160 | var bytePosition = position + (bitPosition >> 3); 161 | setIndex(bytePosition); 162 | 163 | bitPosition = bitPosition - ((bitPosition >> 3) << 3); 164 | 165 | var bits = byte2Bits(this.dataView.getUint8(this.index)); 166 | 167 | if ((bitPosition + count)>8) bits = bits.concat(byte2Bits(this.dataView.getUint8(this.index+1))); 168 | 169 | return bits2Int(bits.slice(bitPosition,bitPosition+count)); 170 | }; 171 | 172 | obj.clear = function(length){ 173 | obj.fill(0,length); 174 | }; 175 | 176 | obj.fill = function(value,length){ 177 | value = value || 0; 178 | length = length || 0; 179 | for (var i = 0; i= (this.length-margin); 187 | }; 188 | 189 | function setIndex(value){ 190 | value = value === 0 ? value : value || obj.index; 191 | if (value<0) value = 0; 192 | if (value >= obj.length) value = obj.length-1; 193 | 194 | obj.index = value; 195 | } 196 | 197 | obj.buffer = arrayBuffer; 198 | obj.dataView = new DataView(arrayBuffer); 199 | obj.length = arrayBuffer.byteLength; 200 | 201 | return obj; 202 | 203 | // todo 204 | /* 205 | 206 | check if copying typed arraybuffers is faster then reading dataview 207 | 208 | var dstU8 = new Uint8Array(dst, dstOffset, byteLength); 209 | var srcU8 = new Uint8Array(src, srcOffset, byteLength); 210 | dstU8.set(srcU8); 211 | 212 | */ 213 | 214 | function byte2Bits(b){ 215 | return [ 216 | b>>7 & 1, 217 | b>>6 & 1, 218 | b>>5 & 1, 219 | b>>4 & 1, 220 | b>>3 & 1, 221 | b>>2 & 1, 222 | b>>1 & 1, 223 | b & 1 224 | ] 225 | } 226 | 227 | function bits2Int(bits){ 228 | var v = 0; 229 | var len = bits.length-1; 230 | for (var i = 0; i<=len ; i++){ 231 | v += bits[i] << (len-i); 232 | } 233 | return v; 234 | } 235 | } 236 | 237 | function loadFile(url,next) { 238 | var req = new XMLHttpRequest(); 239 | req.open("GET", url, true); 240 | req.responseType = "arraybuffer"; 241 | req.onload = function (event) { 242 | var arrayBuffer = req.response; 243 | if (arrayBuffer) { 244 | if (next) next(arrayBuffer); 245 | } else { 246 | console.error("unable to load", url); 247 | if (next) next(false); 248 | } 249 | }; 250 | req.send(null); 251 | } 252 | 253 | function saveFile(b,filename){ 254 | //NOTE: this doesn't work on all browsers, a more robust way is to use the filesaver.js of Eli Grey 255 | var a = document.createElement("a"); 256 | document.body.appendChild(a); 257 | a.style = "display: none"; 258 | url = window.URL.createObjectURL(b); 259 | a.href = url; 260 | a.download = filename; 261 | a.click(); 262 | window.URL.revokeObjectURL(url); 263 | } 264 | 265 | -------------------------------------------------------------------------------- /script/filehandlers/amos.js: -------------------------------------------------------------------------------- 1 | var AMOS = function(){ 2 | 3 | // see http://alvyn.sourceforge.net/amos_file_formats.html 4 | 5 | var me = {}; 6 | 7 | me.fileTypes={ 8 | AMBK: {name: "Amos Pac.Pic file"}, 9 | AMSP: {name: "Amos Sprite bank", inspect:true}, 10 | AMIC: {name: "Amos Icon bank"} 11 | }; 12 | 13 | me.detect=function(file){ 14 | 15 | var id = file.readString(4,0); 16 | 17 | if (id === "AmBk") return FILETYPE.AMBK; 18 | if (id === "AmSp") return FILETYPE.AMSP; 19 | if (id === "AmIc") return FILETYPE.AMIC; 20 | }; 21 | 22 | me.inspect = function(file){ 23 | var result = ""; 24 | 25 | var id = file.readString(4,0); 26 | if (id === "AmSp"){ 27 | var count = file.readWord(); 28 | result = "containing " + count + " sprites"; 29 | } 30 | 31 | return result; 32 | }; 33 | 34 | if (FileType) FileType.register(me); 35 | 36 | return me; 37 | }(); -------------------------------------------------------------------------------- /script/filehandlers/detect.js: -------------------------------------------------------------------------------- 1 | var FILETYPE={ 2 | unknown: 0 3 | }; 4 | 5 | var FileType = function(){ 6 | var me = {}; 7 | 8 | var fileTypeCounter = 1; 9 | var handlers = []; 10 | 11 | me.register = function(handler){ 12 | if (handler.fileTypes){ 13 | for (var key in handler.fileTypes){ 14 | if (handler.fileTypes.hasOwnProperty(key)){ 15 | fileTypeCounter++; 16 | var type = handler.fileTypes[key]; 17 | FILETYPE[key] = { 18 | id: fileTypeCounter, 19 | name: type.name, 20 | handler: handler, 21 | actions: type.actions, 22 | inspect: type.inspect 23 | } 24 | } 25 | } 26 | } 27 | handlers.push(handler); 28 | }; 29 | 30 | me.detect = function(fileData){ 31 | var file = BinaryStream(fileData.buffer,true); 32 | var fileFormat; 33 | 34 | for (var i = 0, max = handlers.length;i 9 | 10 | */ 11 | 12 | var DMS = function() { 13 | 14 | var me = {}; 15 | 16 | me.fileTypes={ 17 | DMS: {name: "Disk Masher File"} 18 | }; 19 | 20 | me.detect=function(file){ 21 | var id = file.readString(4); 22 | if (id === "DMS!"){ 23 | return FILETYPE.DMS; 24 | } 25 | }; 26 | 27 | const DMS_LOG = false; 28 | 29 | /* Functions return codes */ 30 | const NO_PROBLEM = 0; 31 | const DMS_FILE_END = 1; 32 | const ERR_NOMEMORY = 2; 33 | const ERR_CANTOPENIN = 3; 34 | const ERR_CANTOPENOUT = 4; 35 | const ERR_NOTDMS = 5; 36 | const ERR_SREAD = 6; 37 | const ERR_HCRC = 7; 38 | const ERR_NOTTRACK = 8; 39 | const ERR_BIGTRACK = 9; 40 | const ERR_THCRC = 10; 41 | const ERR_TDCRC = 11; 42 | const ERR_CSUM = 12; 43 | const ERR_CANTWRITE = 13; 44 | const ERR_BADDECR = 14; 45 | const ERR_UNKNMODE = 15; 46 | const ERR_NOPASSWD = 16; 47 | const ERR_BADPASSWD = 17; 48 | const ERR_FMS = 18; 49 | const ERR_GZIP = 19; 50 | const ERR_READDISK = 20; 51 | 52 | /* Command to execute */ 53 | const CMD_VIEW = 1; 54 | const CMD_VIEWFULL = 2; 55 | const CMD_SHOWDIZ = 3; 56 | const CMD_SHOWBANNER = 4; 57 | const CMD_TEST = 5; 58 | const CMD_UNPACK = 6; 59 | const CMD_UNPKGZ = 7; 60 | const CMD_EXTRACT = 8; 61 | 62 | const OPT_VERBOSE = 1; 63 | const OPT_QUIET = 2; 64 | 65 | 66 | /*---------------------------------*/ 67 | /* support */ 68 | 69 | const d_code = [ 70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 72 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 74 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 75 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 76 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 77 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 78 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 79 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 80 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 81 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 82 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 83 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 84 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 85 | 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 86 | 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 87 | 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 88 | 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 89 | 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 90 | 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 91 | 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 92 | 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 93 | 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 94 | 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 95 | 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, 96 | 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 97 | 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 98 | 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 99 | 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 100 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 101 | 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F 102 | ]; 103 | const d_len = [ 104 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 105 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 106 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 107 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 108 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 109 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 110 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 111 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 112 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 113 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 114 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 115 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 116 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 117 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 118 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 119 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 120 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 121 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 122 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 123 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 124 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 125 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 126 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 127 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 128 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 129 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 130 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 131 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 132 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 133 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 134 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 135 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 136 | ]; 137 | 138 | const LOC_QUICK = 0; 139 | const LOC_MEDIUM = 1; 140 | const LOC_HEAVY = 2; 141 | const LOC_DEEP = 3; 142 | var dms_loc = new Uint16Array(4); //OWN 143 | 144 | const dms_mask_bits = [ 145 | 0x000000,0x000001,0x000003,0x000007,0x00000f,0x00001f, 146 | 0x00003f,0x00007f,0x0000ff,0x0001ff,0x0003ff,0x0007ff, 147 | 0x000fff,0x001fff,0x003fff,0x007fff,0x00ffff,0x01ffff, 148 | 0x03ffff,0x07ffff,0x0fffff,0x1fffff,0x3fffff,0x7fffff, 149 | 0xffffff 150 | ]; 151 | var dms_indata = null; 152 | var dms_indata_pos = 0; //OWN 153 | var dms_bitcount = 0; 154 | var dms_bitbuf = 0; //u32 155 | 156 | function GETBITS(n) { 157 | return (dms_bitbuf >>> (dms_bitcount - n)) & 0xffff; 158 | } 159 | function DROPBITS(n) { 160 | dms_bitcount -= n; 161 | dms_bitbuf = dms_bitbuf & dms_mask_bits[dms_bitcount]; 162 | while (dms_bitcount < 16) { 163 | dms_bitbuf = ((dms_bitbuf << 8) | dms_indata[dms_indata_pos++]) >>> 0; 164 | dms_bitcount += 8; 165 | } 166 | } 167 | 168 | function initbitbuf(id) { 169 | dms_bitbuf = 0; 170 | dms_bitcount = 0; 171 | dms_indata = id; 172 | dms_indata_pos = 0; 173 | DROPBITS(0); 174 | } 175 | 176 | /*---------------------------------*/ 177 | /* Run Length Encoding */ 178 | 179 | function Unpack_RLE(src, dst, origsize) { 180 | var srco = 0, dsto = 0; 181 | var n = 0; //u16 182 | var a = 0, b = 0; 183 | 184 | while (dsto < origsize){ 185 | if ((a = src[srco++]) != 0x90) 186 | dst[dsto++] = a; 187 | else if (!(b = src[srco++])) 188 | dst[dsto++] = a; 189 | else { 190 | a = src[srco++]; 191 | if (b == 0xff) { 192 | n = src[srco++]; 193 | n = (n << 8) + src[srco++]; 194 | } else 195 | n = b; 196 | if (dsto + n > origsize) return 1; 197 | //memset(dst,a,n); 198 | memset(dst,dsto, a, n); 199 | dsto += n; 200 | } 201 | } 202 | return 0; 203 | } 204 | 205 | /*---------------------------------*/ 206 | /* Quick */ 207 | 208 | const QBITMASK = 0xff; 209 | 210 | function Unpack_QUICK(src, dst, origsize){ 211 | var dsto = 0; 212 | var i = 0, j = 0; 213 | 214 | initbitbuf(src); 215 | while (dsto < origsize) { 216 | if (GETBITS(1) != 0) { 217 | DROPBITS(1); 218 | dst[dsto++] = dms_text[dms_loc[LOC_QUICK]++ & QBITMASK] = GETBITS(8) & 0xff; DROPBITS(8); 219 | } else { 220 | DROPBITS(1); 221 | j = GETBITS(2) + 2; DROPBITS(2); 222 | i = dms_loc[LOC_QUICK] - GETBITS(8) - 1; DROPBITS(8); 223 | while (j--) { 224 | dst[dsto++] = dms_text[dms_loc[LOC_QUICK]++ & QBITMASK] = dms_text[i++ & QBITMASK]; 225 | } 226 | } 227 | } 228 | dms_loc[LOC_QUICK] = dms_loc[LOC_QUICK] + 5 & QBITMASK; 229 | return 0; 230 | } 231 | 232 | /*---------------------------------*/ 233 | /* Medium */ 234 | 235 | const MBITMASK = 0x3fff; 236 | 237 | function Unpack_MEDIUM(src, dst, origsize) { 238 | var dsto = 0; 239 | var i = 0, j = 0, c = 0; 240 | 241 | initbitbuf(src); 242 | while (dsto < origsize) { 243 | if (GETBITS(1) != 0) { 244 | DROPBITS(1); 245 | dst[dsto++] = dms_text[dms_loc[LOC_MEDIUM]++ & MBITMASK] = GETBITS(8) & 0xff; 246 | DROPBITS(8); 247 | } else { 248 | DROPBITS(1); 249 | c = GETBITS(8); DROPBITS(8); 250 | j = d_code[c] + 3; 251 | u = d_len[c]; 252 | c = ((c << u) | GETBITS(u)) & 0xff; DROPBITS(u); 253 | u = d_len[c]; 254 | c = (d_code[c] << 8) | (((c << u) | GETBITS(u)) & 0xff); DROPBITS(u); 255 | i = dms_loc[LOC_MEDIUM] - c - 1; 256 | 257 | while (j--) dst[dsto++] = dms_text[dms_loc[LOC_MEDIUM]++ & MBITMASK] = dms_text[i++ & MBITMASK]; 258 | 259 | } 260 | } 261 | dms_loc[LOC_MEDIUM] = dms_loc[LOC_MEDIUM] + 66 & MBITMASK; 262 | return 0; 263 | } 264 | 265 | /*---------------------------------*/ 266 | /* Deep, Lempel-Ziv-DynamicHuffman decompression */ 267 | 268 | 269 | /* reported from xDMS v1.3.3 */ 270 | var deep_text_loc; 271 | var init_deep_tabs = 1; 272 | 273 | const DBITMASK = 0x3fff; /* uses 16Kb dictionary */ 274 | 275 | const F = 60; /* lookahead buffer size */ 276 | const THRESHOLD = 2; 277 | const N_CHAR = 256 - THRESHOLD + F; /* kinds of characters (character code = 0..N_CHAR-1) */ 278 | const T = N_CHAR * 2 - 1; /* size of table */ 279 | const R = T - 1; /* position of root */ 280 | const MAX_FREQ = 0x8000; /* updates tree when the */ 281 | 282 | var freq = new Uint16Array(T + 1); /* frequency table */ 283 | /* pointers to parent nodes, except for the */ 284 | /* elements [T..T + N_CHAR - 1] which are used to get */ 285 | /* the positions of leaves corresponding to the codes. */ 286 | var prnt = new Uint16Array(T + N_CHAR); 287 | var son = new Uint16Array(T); /* pointers to child nodes (son[], son[] + 1) */ 288 | 289 | 290 | 291 | function Init_DEEP_Tabs(){ 292 | var i = 0; 293 | var j = 0; 294 | 295 | for (i = 0; i < N_CHAR; i++) { 296 | freq[i] = 1; 297 | son[i] = USHORT(i + T); 298 | prnt[i + T] = i; 299 | } 300 | i = 0; 301 | j = N_CHAR; 302 | while (j <= R) { 303 | freq[j] = USHORT(freq[i] + freq[i + 1]); 304 | son[j] = i; 305 | prnt[i] = prnt[i + 1] = j; 306 | i += 2; j++; 307 | } 308 | freq[T] = 0xffff; 309 | prnt[R] = 0; 310 | 311 | init_deep_tabs = 0; 312 | } 313 | 314 | 315 | function Unpack_DEEP(src, dst, origsize){ 316 | var i = 0, j = 0, c = 0; 317 | var dsto = 0; 318 | 319 | initbitbuf(src); 320 | if (init_deep_tabs) Init_DEEP_Tabs(); 321 | 322 | while (dsto < origsize) { 323 | c = DecodeChar(); 324 | if (c < 256) { 325 | dst[dsto++] = dms_text[deep_text_loc++ & DBITMASK] = c & 0xff; 326 | } else { 327 | j = (c - 255 + THRESHOLD); 328 | i = (deep_text_loc - DecodePosition() - 1); 329 | while (j--) { 330 | dst[dsto++] = dms_text[deep_text_loc++ & DBITMASK] = dms_text[i++ & DBITMASK]; 331 | } 332 | } 333 | } 334 | 335 | deep_text_loc = (deep_text_loc + 60 & DBITMASK); 336 | 337 | return 0; 338 | } 339 | 340 | function DecodeChar(){ 341 | var c = son[R]; 342 | 343 | /* travel from root to leaf, */ 344 | /* choosing the smaller child node (son[]) if the read bit is 0, */ 345 | /* the bigger (son[]+1} if 1 */ 346 | while (c < T) { 347 | c = son[c + GETBITS(1)]; 348 | DROPBITS(1); 349 | } 350 | c -= T; 351 | update(c); 352 | return c; 353 | } 354 | 355 | function DecodePosition(){ 356 | var i = GETBITS(8); DROPBITS(8); 357 | var c = (d_code[i] << 8); 358 | var j = d_len[i]; 359 | i = USHORT(((i << j) | GETBITS(j)) & 0xff); DROPBITS(j); 360 | 361 | return (c | i); 362 | } 363 | 364 | 365 | /* reconstruction of tree */ 366 | 367 | function reconst(){ 368 | var i = 0, j = 0, k = 0, f = 0, l = 0, m = 0; 369 | 370 | /* collect leaf nodes in the first half of the table */ 371 | /* and replace the freq by (freq + 1) / 2. */ 372 | for (i = 0; i < T; i++) { 373 | if (son[i] >= T) { 374 | freq[j] = ((freq[i] + 1) >> 1); 375 | son[j] = son[i]; 376 | j++; 377 | } 378 | } 379 | 380 | /* begin constructing tree by connecting sons */ 381 | for (i = 0, j = N_CHAR; j < T; i += 2, j++) { 382 | k = (i + 1); 383 | f = freq[j] = (freq[i] + freq[k]); 384 | for (k = (j - 1); f < freq[k]; k--); 385 | k++; 386 | l = ((j - k) << 1); 387 | //l = j - k; 388 | //memmove(&freq[k + 1], &freq[k], (size_t)l); 389 | for (m = l-1; m >= 0; m--) freq[k + m + 1] = freq[k + m]; 390 | freq[k] = f; 391 | //memmove(&son[k + 1], &son[k], (size_t)l); 392 | for (m = l-1; m >= 0; m--) son[k + m + 1] = son[k + m]; 393 | son[k] = i; 394 | } 395 | /* connect prnt */ 396 | for (i = 0; i < T; i++) { 397 | if ((k = son[i]) >= T) { 398 | prnt[k] = i; 399 | } else { 400 | prnt[k] = prnt[k + 1] = i; 401 | } 402 | } 403 | } 404 | 405 | /* increment frequency of given code by one, and update tree */ 406 | 407 | function update(c){ 408 | var i = 0, j = 0, k = 0, l = 0; 409 | 410 | if (freq[R] == MAX_FREQ) 411 | reconst(); 412 | 413 | c = prnt[c + T]; 414 | do { 415 | k = ++freq[c]; 416 | 417 | /* if the order is disturbed, exchange nodes */ 418 | 419 | if (k > freq[l = (c + 1)]) { 420 | while (k > freq[++l]); 421 | l--; 422 | freq[c] = freq[l]; 423 | freq[l] = k; 424 | 425 | i = son[c]; 426 | prnt[i] = l; 427 | if (i < T) prnt[i + 1] = l; 428 | 429 | j = son[l]; 430 | son[l] = i; 431 | 432 | prnt[j] = c; 433 | if (j < T) prnt[j + 1] = c; 434 | son[c] = j; 435 | 436 | c = l; 437 | } 438 | } while ((c = prnt[c]) != 0); /* repeat up to root */ 439 | } 440 | 441 | 442 | 443 | 444 | /*---------------------------------*/ 445 | /* Heavy, Lempel-Ziv-Huffman decompression */ 446 | 447 | const NC = 510; 448 | const NPT = 20; 449 | const N1 = 510; 450 | const OFFSET = 253; 451 | 452 | var c_len = new Uint8Array(NC); 453 | var c_table = new Uint16Array(4096); 454 | var pt_len = new Uint8Array(NPT); 455 | var pt_table = new Uint16Array(256); 456 | 457 | var dms_left = new Uint16Array(2 * NC - 1); 458 | var dms_right = new Uint16Array(2 * NC - 1 + 9); 459 | var dms_lastlen = 0, dms_np = 0; //u16 460 | 461 | function dms_make_table(nchar, bitlen, tablebits, table) { 462 | var c = 0; //s16 463 | var n = 0, tblsiz = 0, len = 0, depth = 0, maxdepth = 0, avail = 0; //u16 464 | var codeword = 0, bit = 0, tbl = null, err = 0; //u16 465 | var blen = null; //u8 * 466 | 467 | function mktbl() { 468 | var i = 0; 469 | 470 | if (err) return 0; 471 | 472 | if (len == depth) { 473 | while (++c < n) 474 | if (blen[c] == len) { 475 | i = codeword; 476 | codeword += bit; 477 | if (codeword > tblsiz) { 478 | err = 1; 479 | return 0; 480 | } 481 | while (i < codeword) tbl[i++] = c; 482 | return c; 483 | } 484 | c = -1; 485 | len++; 486 | bit >>= 1; 487 | } 488 | depth++; 489 | if (depth < maxdepth) { 490 | mktbl(); 491 | mktbl(); 492 | } else if (depth > 32) { 493 | err = 2; 494 | return 0; 495 | } else { 496 | if ((i = avail++) >= 2 * n - 1) { 497 | err = 3; 498 | return 0; 499 | } 500 | dms_left[i] = mktbl(); 501 | dms_right[i] = mktbl(); 502 | if (codeword >= tblsiz) { 503 | err = 4; 504 | return 0; 505 | } 506 | if (depth == maxdepth) tbl[codeword++] = i; 507 | } 508 | depth--; 509 | return i; 510 | } 511 | 512 | n = avail = nchar; 513 | blen = bitlen; 514 | tbl = table; 515 | tblsiz = 1 << tablebits; 516 | bit = tblsiz >> 1; 517 | maxdepth = tablebits + 1; 518 | depth = len = 1; 519 | c = -1; 520 | codeword = 0; 521 | err = 0; 522 | mktbl(); // left subtree 523 | if (err) return err; 524 | mktbl(); // right subtree 525 | if (err) return err; 526 | if (codeword != tblsiz) return 5; 527 | return 0; 528 | } 529 | 530 | function read_tree_c() { 531 | var n = GETBITS(9); 532 | DROPBITS(9); 533 | if (n > 0) { 534 | for (var i = 0; i < n; i++) { 535 | c_len[i] = GETBITS(5) & 0xff; 536 | DROPBITS(5); 537 | } 538 | for (i = n; i < 510; i++) c_len[i] = 0; 539 | if (dms_make_table(510, c_len, 12, c_table)) return 1; 540 | } else { 541 | n = GETBITS(9); 542 | DROPBITS(9); 543 | for (var i = 0; i < 510; i++) c_len[i] = 0; 544 | for (i = 0; i < 4096; i++) c_table[i] = n; 545 | } 546 | return 0; 547 | } 548 | function read_tree_p() { 549 | var n = GETBITS(5); 550 | DROPBITS(5); 551 | if (n > 0){ 552 | for (var i = 0; i < n; i++) { 553 | pt_len[i] = GETBITS(4) & 0xff; 554 | DROPBITS(4); 555 | } 556 | for (i = n; i < dms_np; i++) pt_len[i] = 0; 557 | if (dms_make_table(dms_np, pt_len, 8, pt_table)) return 1; 558 | } else { 559 | n = GETBITS(5); 560 | DROPBITS(5); 561 | for (var i = 0; i < dms_np; i++) pt_len[i] = 0; 562 | for (i = 0; i < 256; i++) pt_table[i] = n; 563 | } 564 | return 0; 565 | } 566 | 567 | function decode_c(){ 568 | var j = c_table[GETBITS(12)]; 569 | if (j < N1) { 570 | DROPBITS(c_len[j]); 571 | } else { 572 | DROPBITS(12); 573 | var i = GETBITS(16); 574 | var m = 0x8000; 575 | do { 576 | if (i & m) j = dms_right[j]; 577 | else j = dms_left [j]; 578 | m >>= 1; 579 | } while (j >= N1); 580 | DROPBITS(c_len[j] - 12); 581 | } 582 | return j; 583 | } 584 | function decode_p(){ 585 | var j = pt_table[GETBITS(8)]; 586 | if (j < dms_np) { 587 | DROPBITS(pt_len[j]); 588 | } else { 589 | DROPBITS(8); 590 | var i = GETBITS(16); 591 | var m = 0x8000; 592 | do { 593 | if (i & m) j = dms_right[j]; 594 | else j = dms_left [j]; 595 | m >>= 1; 596 | } while (j >= dms_np); 597 | DROPBITS(pt_len[j] - 8); 598 | } 599 | if (j != dms_np-1) { 600 | if (j > 0) { 601 | j = GETBITS(i = j-1) | (1 << (j-1)); 602 | DROPBITS(i); 603 | } 604 | dms_lastlen = j; 605 | } 606 | return dms_lastlen; 607 | } 608 | 609 | function Unpack_HEAVY(src, dst, flags, origsize){ 610 | /* Heavy 1 uses a 4Kb dictionary, Heavy 2 uses 8Kb */ 611 | if (flags & 8) { 612 | dms_np = 15; 613 | var bitmask = 0x1fff; 614 | } else { 615 | dms_np = 14; 616 | var bitmask = 0x0fff; 617 | } 618 | initbitbuf(src); 619 | 620 | if (flags & 2) { 621 | if (read_tree_c()) return 1; 622 | if (read_tree_p()) return 2; 623 | } 624 | 625 | var dsto = 0; 626 | while (dsto < origsize) { 627 | var c = decode_c(); 628 | if (c < 256) { 629 | dst[dsto++] = dms_text[dms_loc[LOC_HEAVY]++ & bitmask] = c; 630 | } else { 631 | var j = c - OFFSET; 632 | var i = dms_loc[LOC_HEAVY] - decode_p() - 1; 633 | while (j--) dst[dsto++] = dms_text[dms_loc[LOC_HEAVY]++ & bitmask] = dms_text[i++ & bitmask]; 634 | } 635 | } 636 | return 0; 637 | } 638 | 639 | /*---------------------------------*/ 640 | 641 | function Init_Decrunchers() { 642 | dms_loc[LOC_QUICK] = 251; 643 | 644 | dms_loc[LOC_MEDIUM] = 0x3fbe; 645 | 646 | dms_loc[LOC_HEAVY] = 0; 647 | dms_lastlen = 0; 648 | dms_np = 0; 649 | 650 | deep_text_loc = 0x3fc4; 651 | init_deep_tabs = 1; 652 | 653 | //memset(dms_text,0,0x3fc8); 654 | memset(dms_text,0, 0, 0x3fc8); 655 | } 656 | 657 | /*-----------------------------------------------------------------------*/ 658 | 659 | const HEADLEN = 56; 660 | const THLEN = 20; 661 | const TRACK_BUFFER_LEN = 32000; 662 | const TEMP_BUFFER_LEN = 32000; 663 | 664 | const DMSFLAG_ENCRYPTED = 2; 665 | const DMSFLAG_HD = 16; 666 | 667 | const DMS_MAX_EXTRA = 10; 668 | 669 | const modes = ["NOCOMP", "SIMPLE", "QUICK ", "MEDIUM", "DEEP ", "HEAVY1", "HEAVY2"]; 670 | 671 | var PWDCRC = 0; //u16 672 | var passfound = 0, passretries = 0; 673 | 674 | var dms_text = null; //u8 * 675 | 676 | /*---------------------------------*/ 677 | 678 | function ctime(t){ 679 | var a = new Date(t * 1000); 680 | var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; 681 | var year = a.getFullYear(); 682 | var month = months[a.getMonth()]; 683 | var date = a.getDate(); 684 | var hour = a.getHours(); 685 | var min = a.getMinutes(); 686 | var sec = a.getSeconds(); 687 | return date + ' ' + month + ' ' + year + ' ' + hour + ":" + min + ":" + sec; 688 | } 689 | 690 | /*---------------------------------*/ 691 | 692 | function log_error(track) { 693 | console.warn("DMS() Ignored error on track " + track); 694 | } 695 | 696 | 697 | 698 | /*---------------------------------*/ 699 | 700 | function dms_Calc_CheckSum(mem, size){ 701 | var u = 0; //u16 702 | var p = 0; 703 | while (size--) { 704 | u += mem[p++]; 705 | if (u > 0xffff) u -= 0x10000; 706 | } 707 | return u; //(u & 0xffff); 708 | } 709 | 710 | /*---------------------------------*/ 711 | 712 | const CRCTab = [ 713 | 0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241, 714 | 0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440, 715 | 0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40, 716 | 0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841, 717 | 0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40, 718 | 0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41, 719 | 0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641, 720 | 0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040, 721 | 0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240, 722 | 0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441, 723 | 0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41, 724 | 0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840, 725 | 0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41, 726 | 0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40, 727 | 0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640, 728 | 0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041, 729 | 0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240, 730 | 0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441, 731 | 0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41, 732 | 0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840, 733 | 0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41, 734 | 0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40, 735 | 0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640, 736 | 0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041, 737 | 0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241, 738 | 0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440, 739 | 0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40, 740 | 0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841, 741 | 0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40, 742 | 0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41, 743 | 0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641, 744 | 0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040 745 | ]; 746 | function dms_CreateCRC(mem,memo, size) { 747 | var CRC = 0; 748 | 749 | while (size--) 750 | CRC = CRCTab[(CRC ^ mem[memo++]) & 255] ^ ((CRC >> 8) & 255); 751 | 752 | return CRC; 753 | } 754 | 755 | /*---------------------------------*/ 756 | 757 | function addextra(name, extra, p, size) { 758 | 759 | console.log("add extra " + size); 760 | if (extra === null) 761 | return; 762 | for (var i = 0; i < DMS_MAX_EXTRA; i++) { 763 | if (extra[i] === null) 764 | break; 765 | } 766 | if (i == DMS_MAX_EXTRA) 767 | return; 768 | 769 | var arrayBufferOut = new ArrayBuffer(size); 770 | var zf = new BinaryStream(arrayBufferOut,true); 771 | zf.name = name; 772 | 773 | 774 | fwrite(p,0, size, 1, zf); 775 | zf.goto(0); 776 | extra[i] = zf; 777 | } 778 | 779 | /*---------------------------------*/ 780 | 781 | /* DMS uses a lame encryption */ 782 | function dms_decrypt(p, len, src){ 783 | var srco = 0, po = 0; 784 | var t = 0; //u16 785 | 786 | while (len--) { 787 | t = src[srco++]; 788 | p[po++] = t ^ (PWDCRC & 0xff); 789 | PWDCRC = ((PWDCRC >> 1) + t) & 0xffff; 790 | } 791 | } 792 | 793 | function Unpack_Track_2(b1, b2, pklen2, unpklen, cmode, flags){ 794 | switch (cmode){ 795 | case 0: 796 | /* No Compression */ 797 | //b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen); 798 | memCopy(b2,b1,unpklen); 799 | break; 800 | case 1: 801 | /* Simple Compression */ 802 | if (Unpack_RLE(b1, b2, unpklen)) return ERR_BADDECR; 803 | break; 804 | case 2: 805 | /* Quick Compression */ 806 | if (Unpack_QUICK(b1, b2, pklen2)) return ERR_BADDECR; 807 | if (Unpack_RLE(b2, b1, unpklen)) return ERR_BADDECR; 808 | //b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen); 809 | memCopy(b2,b1,unpklen); 810 | break; 811 | case 3: 812 | /* Medium Compression */ 813 | if (Unpack_MEDIUM(b1, b2, pklen2)) return ERR_BADDECR; 814 | if (Unpack_RLE(b2, b1, unpklen)) return ERR_BADDECR; 815 | //b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen); 816 | memCopy(b2,b1,unpklen); 817 | break; 818 | case 4: 819 | /* Deep Compression */ 820 | if (Unpack_DEEP(b1, b2, pklen2)) return ERR_BADDECR; 821 | if (Unpack_RLE(b2, b1, unpklen)) return ERR_BADDECR; 822 | //b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen); 823 | memCopy(b2,b1,unpklen); 824 | break; 825 | case 5: 826 | case 6: 827 | /* Heavy Compression */ 828 | if (cmode == 5) { 829 | /* Heavy 1 */ 830 | if (Unpack_HEAVY(b1,b2,flags & 7,pklen2)) return ERR_BADDECR; 831 | } else { 832 | /* Heavy 2 */ 833 | if (Unpack_HEAVY(b1,b2,flags | 8,pklen2)) return ERR_BADDECR; 834 | } 835 | if (flags & 4) { 836 | //memset(b1, 0, unpklen); 837 | memset(b1,0, 0, unpklen); 838 | /* Unpack with RLE only if this flag is set */ 839 | if (Unpack_RLE(b2, b1, unpklen)) return ERR_BADDECR; 840 | //b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen); 841 | memCopy(b2,b1,unpklen); 842 | } 843 | break; 844 | default: 845 | return ERR_UNKNMODE; 846 | } 847 | if (!(flags & 1)) 848 | Init_Decrunchers(); 849 | 850 | return NO_PROBLEM; 851 | } 852 | 853 | var pass = 0; 854 | function Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum1, enc) { 855 | //static USHORT pass; 856 | var r = 0, err = NO_PROBLEM; 857 | var prevpass = 0; 858 | 859 | if (passfound) { 860 | if (number != 80) 861 | dms_decrypt(b1, pklen1, b1); 862 | r = Unpack_Track_2(b1, b2, pklen2, unpklen, cmode, flags); 863 | if (r == NO_PROBLEM) { 864 | if (usum1 == dms_Calc_CheckSum(b2, unpklen)) 865 | return NO_PROBLEM; 866 | } 867 | log_error(number); 868 | if (passretries <= 0) 869 | return ERR_CSUM; 870 | } 871 | 872 | passretries--; 873 | var pwrounds = 0; 874 | var maybeencrypted = 0; 875 | //UCHAR *tmp = (unsigned char*)malloc (pklen1); 876 | var tmp = new Uint8Array(pklen1); 877 | //tmp.set(b1.subarray(0, pklen1)); //memcpy(tmp, b1, pklen1); 878 | memCopy(tmp,b1,pklen1); 879 | 880 | memset(b2,0, 0, unpklen); 881 | for (;;) { 882 | console.log("unpacking"); 883 | r = Unpack_Track_2(b1, b2, pklen2, unpklen, cmode, flags); 884 | if (r == NO_PROBLEM) { 885 | if (usum1 == dms_Calc_CheckSum(b2, unpklen)) { 886 | passfound = maybeencrypted; 887 | if (passfound) 888 | console.log("DMS() decryption key = " + prevpass); 889 | err = NO_PROBLEM; 890 | pass = prevpass; 891 | break; 892 | } 893 | } 894 | if (number == 80 || !enc) { 895 | err = ERR_CSUM; 896 | break; 897 | } 898 | maybeencrypted = 1; 899 | prevpass = pass; 900 | PWDCRC = pass; 901 | pass++; 902 | dms_decrypt(b1, pklen1, tmp); 903 | pwrounds++; 904 | if (pwrounds == 65536) { 905 | err = ERR_CSUM; 906 | passfound = 0; 907 | break; 908 | } 909 | } 910 | //free(tmp); 911 | return err; 912 | } 913 | 914 | function Process_Track(fi, fo, b1, b2, cmd, opt, dmsflags, extra){ 915 | var crcerr = 0; 916 | 917 | var l = fread(b1, 1, THLEN, fi); 918 | if (l != THLEN) { 919 | if (l == 0) 920 | return DMS_FILE_END; 921 | else 922 | return ERR_SREAD; 923 | } 924 | 925 | /* "TR" identifies a Track Header */ 926 | if ((b1[0] != 84) || (b1[1] != 82)) 927 | return ERR_NOTTRACK; 928 | 929 | /* Track Header CRC */ 930 | var hcrc = ((b1[THLEN-2] << 8) | b1[THLEN-1]); 931 | 932 | if (dms_CreateCRC(b1,0, THLEN-2) != hcrc) 933 | return ERR_THCRC; 934 | 935 | var number = (b1[2] << 8) | b1[3]; /* Number of track */ 936 | var pklen1 = (b1[6] << 8) | b1[7]; /* Length of packed track data as in archive */ 937 | var pklen2 = (b1[8] << 8) | b1[9]; /* Length of data after first unpacking */ 938 | var unpklen = (b1[10] << 8) | b1[11]; /* Length of data after subsequent rle unpacking */ 939 | var flags = b1[12]; /* control flags */ 940 | var cmode = b1[13]; /* compression mode used */ 941 | var usum = (b1[14] << 8) | b1[15]; /* Track Data CheckSum AFTER unpacking */ 942 | var dcrc = (b1[16] << 8) | b1[17]; /* Track Data CRC BEFORE unpacking */ 943 | 944 | 945 | if (DMS_LOG) { 946 | var out = ""; 947 | if (number == 80) 948 | out += " FileID "; 949 | else if (number == 0xffff) 950 | out += " Banner "; 951 | else if ((number == 0) && (unpklen == 1024)) 952 | out += " FakeBB "; 953 | else 954 | out += number; 955 | 956 | out += pklen1 + ", " + unpklen+ ", " + modes[cmode] + ", " + usum + ", " +hcrc + ", " + dcrc + ", " + flags; 957 | console.log(out); 958 | } 959 | 960 | if ((pklen1 > TRACK_BUFFER_LEN) || (pklen2 > TRACK_BUFFER_LEN) || (unpklen > TRACK_BUFFER_LEN)) 961 | return ERR_BIGTRACK; 962 | 963 | if (fread(b1, 1, pklen1, fi) != pklen1) 964 | return ERR_SREAD; 965 | 966 | if (dms_CreateCRC(b1,0, pklen1) != dcrc) { 967 | log_error(number); 968 | crcerr = 1; 969 | } 970 | /* track 80 is FILEID.DIZ, track 0xffff (-1) is Banner */ 971 | /* and track 0 with 1024 bytes only is a fake boot block with more advertising */ 972 | /* FILE_ID.DIZ is never encrypted */ 973 | 974 | //if (pwd && (number!=80)) dms_decrypt(b1,pklen1); ORG 975 | 976 | var normaltrack = false; 977 | if ((cmd == CMD_UNPACK) && (number < 80) && (unpklen > 2048)) { 978 | //memset(b2, 0, unpklen); 979 | memset(b2,0, 0, unpklen); 980 | if (!crcerr) 981 | Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum, dmsflags & DMSFLAG_ENCRYPTED); 982 | 983 | if (number == 0 && fo.index == 512 * 22) { 984 | // did we have another cylinder 0 already? 985 | fo.goto(0); 986 | 987 | var p = new Uint8Array(512 * 22); 988 | fread(p, 512 * 22, 1, fo); 989 | addextra("BigFakeBootBlock", extra, p, 512 * 22); 990 | //xfree(p); 991 | delete p; 992 | } 993 | 994 | fo.goto(number * 512 * 22 * ((dmsflags & DMSFLAG_HD) ? 2 : 1)); 995 | 996 | if (fwrite(b2,0, 1, unpklen, fo) != unpklen) 997 | return ERR_CANTWRITE; 998 | normaltrack = true; 999 | } else if (number == 0 && unpklen == 1024) { 1000 | //b2.set(0, 0, unpklen); //memset(b2, 0, unpklen); 1001 | memCopy(b2,0,unpklen); 1002 | if (!crcerr) 1003 | Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum, dmsflags & DMSFLAG_ENCRYPTED); 1004 | addextra("FakeBootBlock", extra, b2, unpklen); 1005 | } 1006 | 1007 | if (crcerr) 1008 | return NO_PROBLEM; 1009 | 1010 | if (number == 0xffff) { 1011 | Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum, dmsflags & DMSFLAG_ENCRYPTED); 1012 | if (extra) 1013 | addextra("Banner", extra, b2, unpklen); 1014 | 1015 | //printbandiz(b2, unpklen); 1016 | } 1017 | 1018 | if (number == 80) { 1019 | Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum, dmsflags & DMSFLAG_ENCRYPTED); 1020 | if (extra) 1021 | addextra("FILEID.DIZ", extra, b2, unpklen); 1022 | 1023 | //printbandiz(b2, unpklen); 1024 | } 1025 | 1026 | if (!normaltrack) 1027 | Init_Decrunchers(); 1028 | 1029 | return NO_PROBLEM; 1030 | } 1031 | 1032 | function DMS_Process_File(fi, fo, cmd, opt, PCRC, pwd, part, extra) { 1033 | passfound = 0; 1034 | passretries = 2; 1035 | 1036 | b1 = new Uint8Array(TRACK_BUFFER_LEN); 1037 | b2 = new Uint8Array(TRACK_BUFFER_LEN); 1038 | dms_text = new Uint8Array(TEMP_BUFFER_LEN); 1039 | 1040 | fi.goto(0); 1041 | if (fread(b1, 1, HEADLEN, fi) != HEADLEN) { 1042 | dms_text = null; 1043 | return ERR_SREAD; 1044 | } 1045 | 1046 | /* Check the first 4 bytes of file to see if it is "DMS!" */ 1047 | //if ((b1[0] != 'D') || (b1[1] != 'M') || (b1[2] != 'S') || (b1[3] != '!')) { 1048 | if (!(b1[0] == 68 && b1[1] == 77 && b1[2] == 83 && b1[3] == 33)) { /* DMS! */ 1049 | dms_text = null; 1050 | return ERR_NOTDMS; 1051 | } 1052 | 1053 | /* Header CRC */ 1054 | var hcrc = (b1[HEADLEN - 2] << 8) | b1[HEADLEN - 1]; 1055 | if (hcrc != dms_CreateCRC(b1,4, HEADLEN - 6)) { 1056 | dms_text = null; 1057 | return ERR_HCRC; 1058 | } 1059 | 1060 | var geninfo = (b1[10] << 8) | b1[11]; /* General info about archive */ 1061 | var date = (((b1[12]) << 24) | ((b1[13]) << 16) | ((b1[14]) << 8) | b1[15]) >>> 0; /* date in standard UNIX/ANSI format */ 1062 | var low = (b1[16] << 8) | b1[17]; /* Lowest track in archive. May be incorrect if archive is "appended" */ 1063 | var high = (b1[18] << 8) | b1[19]; /* Highest track in archive. May be incorrect if archive is "appended" */ 1064 | 1065 | if (part && low < 30) { 1066 | dms_text = null; 1067 | return DMS_FILE_END; 1068 | } 1069 | 1070 | var pkfsize = (((b1[21]) << 16) | ((b1[22]) << 8) | b1[23]) >>> 0; /* Length of total packed data as in archive */ 1071 | var unpkfsize = (((b1[25]) << 16) | ((b1[26]) << 8) | b1[27]) >>> 0; /* Length of unpacked data. Usually 901120 bytes */ 1072 | 1073 | var c_version = (b1[46] << 8) | b1[47]; /* version of DMS used to generate it */ 1074 | var disktype = (b1[50] << 8) | b1[51]; /* Type of compressed disk */ 1075 | var cmode = (b1[52] << 8) | b1[53]; /* Compression mode mostly used in this archive */ 1076 | 1077 | PWDCRC = PCRC; 1078 | 1079 | if (DMS_LOG) { 1080 | var pv = Math.floor(c_version / 100); 1081 | 1082 | console.log(" Created with DMS version " + pv + "." + (c_version - pv * 100) + " " + ((geninfo & 0x80) ? "Registered" : "Evaluation")); 1083 | console.log(" Creation date : " + ctime(date) ); 1084 | console.log(" Lowest track in archive : " + low); 1085 | console.log(" Highest track in archive : " + high); 1086 | console.log(" Packed data size : " + pkfsize); 1087 | console.log(" Unpacked data size : " + unpkfsize); 1088 | 1089 | var out = " Disk type of archive : "; 1090 | switch (disktype) { 1091 | case 0: 1092 | case 1: 1093 | /* Can also be a non-dos disk */ 1094 | out += "AmigaOS 1.0 OFS\n"; 1095 | break; 1096 | case 2: 1097 | out += "AmigaOS 2.0 FFS\n"; 1098 | break; 1099 | case 3: 1100 | out += "AmigaOS 3.0 OFS / International\n"; 1101 | break; 1102 | case 4: 1103 | out += "AmigaOS 3.0 FFS / International\n"; 1104 | break; 1105 | case 5: 1106 | out += "AmigaOS 3.0 OFS / Dir Cache\n"; 1107 | break; 1108 | case 6: 1109 | out += "AmigaOS 3.0 FFS / Dir Cache\n"; 1110 | break; 1111 | case 7: 1112 | out += "FMS Amiga System File\n"; 1113 | break; 1114 | default: 1115 | out += "Unknown\n"; 1116 | } 1117 | console.log(out); 1118 | 1119 | out = " Compression mode used : "; 1120 | if (cmode > 6) 1121 | out += "Unknown !\n"; 1122 | else 1123 | out += modes[cmode] + "\n"; 1124 | console.log(out); 1125 | 1126 | out = " General info : "; 1127 | if ((geninfo == 0) || (geninfo == 0x80)) out += "None"; 1128 | if (geninfo & 1) out += "NoZero "; 1129 | if (geninfo & 2) out += "Encrypted "; 1130 | if (geninfo & 4) out += "Appends "; 1131 | if (geninfo & 8) out += "Banner "; 1132 | if (geninfo & 16) out += "HD "; 1133 | if (geninfo & 32) out += "MS-DOS "; 1134 | if (geninfo & 64) out += "DMS_DEV_Fixed "; 1135 | if (geninfo & 256) out += "FILEID.DIZ"; 1136 | out += "\n"; 1137 | console.log(out); 1138 | 1139 | console.log(" Info Header CRC : ", hcrc.toString(16)); 1140 | } 1141 | 1142 | if (disktype == 7) { 1143 | /* It's not a DMS compressed disk image, but a FMS archive */ 1144 | dms_text = null; 1145 | return ERR_FMS; 1146 | } 1147 | 1148 | if (DMS_LOG) { 1149 | console.log(" Track Plength Ulength Cmode USUM HCRC DCRC Cflag\n"); 1150 | console.log(" ------ ------- ------- ------ ---- ---- ---- -----\n"); 1151 | } 1152 | 1153 | // if (((cmd==CMD_UNPACK) || (cmd==CMD_SHOWBANNER)) && (geninfo & 2) && (!pwd)) 1154 | // return ERR_NOPASSWD; 1155 | 1156 | var ret = NO_PROBLEM; 1157 | 1158 | Init_Decrunchers(); 1159 | 1160 | 1161 | if (cmd != CMD_VIEW) { 1162 | if (cmd == CMD_SHOWBANNER) /* Banner is in the first track */ 1163 | ret = Process_Track(fi, null, b1, b2, cmd, opt, geninfo, extra); 1164 | else { 1165 | Init_Decrunchers(); 1166 | for (;;) { 1167 | ret = Process_Track(fi, fo, b1, b2, cmd, opt, geninfo, extra); 1168 | if (ret == DMS_FILE_END) 1169 | break; 1170 | if (ret == NO_PROBLEM){ 1171 | continue; 1172 | } 1173 | break; 1174 | 1175 | } 1176 | } 1177 | } 1178 | if ((cmd == CMD_VIEWFULL) || (cmd == CMD_SHOWDIZ) || (cmd == CMD_SHOWBANNER)) 1179 | console.log("---"); 1180 | 1181 | if (ret == DMS_FILE_END) 1182 | ret = NO_PROBLEM; 1183 | 1184 | /* Used to give an error message, but I have seen some DMS */ 1185 | /* files with texts or zeros at the end of the valid data */ 1186 | /* So, when we find something that is not a track header, */ 1187 | /* we suppose that the valid data is over. And say it's ok. */ 1188 | if (ret == ERR_NOTTRACK) 1189 | ret = NO_PROBLEM; 1190 | 1191 | 1192 | dms_text = null; 1193 | return ret; 1194 | } 1195 | 1196 | me.toADF = function(z, index, retcode) { 1197 | 1198 | if (typeof index == "undefined") index = 0; 1199 | if (typeof retcode == "undefined") retcode = null; 1200 | 1201 | //static int recursive; 1202 | var orgname = z.name || "dms.adf"; 1203 | var newname = ""; 1204 | var zextra = new Array(DMS_MAX_EXTRA); //zfile * 1205 | for (var vi = 0; vi < DMS_MAX_EXTRA; vi++) 1206 | zextra[vi] = null; 1207 | 1208 | //if (checkwrite(z, retcode)) return null; 1209 | //if (recursive) return null; 1210 | 1211 | var ext = orgname.lastIndexOf('.'); 1212 | if (ext != -1) { 1213 | newname = orgname.substr(0, ext); 1214 | newname += ".ADF"; 1215 | } else 1216 | newname = orgname + ".ADF"; 1217 | 1218 | 1219 | var arrayBufferOut = new ArrayBuffer(1760 * 512); 1220 | var zo = new BinaryStream(arrayBufferOut,true); 1221 | zo.name = newname; 1222 | 1223 | pass = 0; 1224 | var ret = DMS_Process_File(z, zo, CMD_UNPACK, OPT_VERBOSE, 0, null, false, zextra); 1225 | if (ret == NO_PROBLEM) { // || ret == DMS_FILE_END) { 1226 | 1227 | zo.goto(0); 1228 | 1229 | if (index > 0) { 1230 | zo = null; 1231 | for (var i = 0; i < DMS_MAX_EXTRA && zextra[i]; i++); 1232 | if (index > i) { 1233 | //goto end; 1234 | return zo; 1235 | } 1236 | zo = zextra[index - 1]; 1237 | zextra[index - 1] = null; 1238 | } 1239 | 1240 | //if (retcode !== null) *retcode = 1; 1241 | 1242 | z = null; 1243 | 1244 | console.log("DMS() converted '"+orgname+"' to '"+newname+"'"); 1245 | } else { 1246 | zo = null; 1247 | 1248 | console.error("Can't convert '"+orgname+"' to ADF. (error "+ret+")"); 1249 | } 1250 | //end: 1251 | console.log("extras:"); 1252 | for (i = 0; i < DMS_MAX_EXTRA; i++){ 1253 | if (zextra[i]) console.log(zextra[i].name); 1254 | } 1255 | 1256 | return zo; 1257 | }; 1258 | 1259 | 1260 | function fread(buffer, l1, lengthToRead, fromFile) { 1261 | 1262 | if (fromFile.index + l1 * lengthToRead > fromFile.length) { 1263 | lengthToRead = l1 ? Math.floor((fromFile.length - fromFile.index) / l1) : 0; 1264 | if (lengthToRead < 0) lengthToRead = 0; 1265 | } 1266 | 1267 | for (var i = 0, max = l1 * lengthToRead; i file.length) { 1282 | 1283 | // TODO: when does this happen ? 1284 | // we just ignore this for now ... 1285 | } 1286 | 1287 | for (var i = 0, max=l1 * l2;i> 4) << 1; // in bytes 261 | var pixels = []; 262 | 263 | for (var plane=0;plane= 0; i--) { 274 | x = (b*8) + (7-i); 275 | var bit = val & (1 << i) ? 1 : 0; 276 | var p = pixels[y][x] || 0; 277 | pixels[y][x] = p + (bit< RLE control chars are 8 bits, but the data elements are n bits, determined by state.depth 346 | 347 | var max = (state.imageSize-1) * 8; 348 | var bitIndex = 0; 349 | 350 | while (bitIndex < max) { 351 | var b = file.readBits(8,bitIndex,imageDataOffset); 352 | bitIndex += 8; 353 | 354 | if (b > 128) { 355 | var b2 = file.readBits(state.depth,bitIndex,imageDataOffset); 356 | bitIndex += state.depth; 357 | for (var k = 0; k < 257 - b; k++) state.pixels.push(b2); 358 | } 359 | if (b < 128) { 360 | for (k = 0; k <= b; k++){ 361 | state.pixels.push(file.readBits(state.depth,bitIndex,imageDataOffset)); 362 | bitIndex += state.depth; 363 | } 364 | } 365 | } 366 | }else{ 367 | // note: uncompressed data is BYTE aligned, even if state.depth < 8 368 | for (var i = 0; i < state.imageSize; i++){ 369 | state.pixels.push(file.readUbyte()) 370 | } 371 | } 372 | 373 | if (state.paletteSize){ 374 | file.goto(paletteDataOffset); 375 | var rgb = []; 376 | 377 | if (state.paletteCompression){ 378 | var max = (state.paletteSize-1) * 8; 379 | var bitIndex = 0; 380 | 381 | while (bitIndex < max) { 382 | var b = file.readBits(8,bitIndex,paletteDataOffset); 383 | bitIndex += 8; 384 | 385 | if (b > 128) { 386 | var b2 = file.readBits(state.depth,bitIndex,paletteDataOffset); 387 | bitIndex += state.depth; 388 | for (var k = 0; k < 257 - b; k++) rgb.push(b2); 389 | } 390 | if (b < 128) { 391 | for (k = 0; k <= b; k++){ 392 | rgb.push(file.readBits(state.depth,bitIndex,paletteDataOffset)); 393 | bitIndex += state.depth; 394 | } 395 | } 396 | } 397 | }else{ 398 | for (i = 0; i < state.paletteSize; i++){ 399 | rgb.push(file.readUbyte()) 400 | } 401 | } 402 | 403 | if (rgb.length>2){ 404 | for (i = 0, max = rgb.length; i>1,c[1]>>1,c[2]>>1] 82 | } 83 | } 84 | img.colorPlanes = img.numPlanes; 85 | if (img.ham){ 86 | img.hamPixels = []; 87 | img.colorPlanes = 6; // HAM8 88 | if (img.numPlanes<7) img.colorPlanes = 4; // HAM6 89 | } 90 | 91 | // some images have bad CAMG blocks? 92 | if (!img.hires && img.width>=640) img.hires=true; 93 | if (img.hires && !img.interlaced && img.height>=400) img.interlaced=true; 94 | 95 | if (decodeBody){ 96 | var lineWidth = (img.width + 15) >> 4; // in words 97 | lineWidth = lineWidth*2; // in bytes 98 | var pixels = []; 99 | 100 | for (var y = 0; y 128) { 112 | var b2 = file.readUbyte(); 113 | for (var k = 0; k < 257 - b; k++) line.push(b2); 114 | } else { 115 | for (k = 0; k <= b; k++) line.push(file.readUbyte()); 116 | } 117 | } 118 | }else{ 119 | for (var x = 0; x= 0; i--) { 126 | x = (b*8) + (7-i); 127 | var bit = val & (1 << i) ? 1 : 0; 128 | if (plane1100){ 14 | id = file.readString(4,1080); 15 | } 16 | 17 | switch (id){ 18 | case "M.K.": 19 | case "M!K!": 20 | case "M&K!": 21 | case "FLT4": 22 | case "2CHN": 23 | case "6CHN": 24 | case "8CHN": 25 | case "10CH": 26 | case "12CH": 27 | case "14CH": 28 | case "16CH": 29 | case "18CH": 30 | case "20CH": 31 | case "22CH": 32 | case "24CH": 33 | case "26CH": 34 | case "28CH": 35 | case "30CH": 36 | case "32CH": 37 | return FILETYPE.MOD; 38 | } 39 | }; 40 | 41 | me.handle = function(file,action){ 42 | console.error("handle",file); 43 | 44 | var playFile = function(){ 45 | if (AdfViewer) AdfViewer.showImage(); 46 | BassoonTracker.load({ 47 | name: "ADF file", 48 | buffer: file.buffer 49 | },true,function(){ 50 | BassoonTracker.playSong(); 51 | }) 52 | }; 53 | 54 | if (typeof BassoonTracker === "undefined"){ 55 | var plugin = "https://www.stef.be/bassoontracker/versions/0.2.0/bassoontracker-min.js"; 56 | loadScript(plugin,function(){ 57 | console.log("Tracker loaded"); 58 | BassoonTracker.init({ 59 | plugin: true, 60 | baseUrl: "https://www.stef.be/bassoontracker/versions/0.2.0/", 61 | canvas: document.getElementById("canvas"), 62 | callback: function(){ 63 | console.log("Tracker init Done"); 64 | playFile(); 65 | } 66 | }) 67 | }); 68 | }else{ 69 | playFile(); 70 | } 71 | }; 72 | 73 | 74 | if (FileType) FileType.register(me); 75 | 76 | return me; 77 | }(); -------------------------------------------------------------------------------- /script/lib/filesaver.js: -------------------------------------------------------------------------------- 1 | /*! @source https://github.com/eligrey/FileSaver.js/blob/master/FileSaver.js */ 2 | var saveAs=saveAs||function(e){"use strict";if(typeof e==="undefined"||typeof navigator!=="undefined"&&/MSIE [1-9]\./.test(navigator.userAgent)){return}var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=t.createElementNS("http://www.w3.org/1999/xhtml","a"),o="download"in r,a=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},i=/constructor/i.test(e.HTMLElement)||e.safari,f=/CriOS\/[\d]+/.test(navigator.userAgent),u=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},s="application/octet-stream",d=1e3*40,c=function(e){var t=function(){if(typeof e==="string"){n().revokeObjectURL(e)}else{e.remove()}};setTimeout(t,d)},l=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var o=e["on"+t[r]];if(typeof o==="function"){try{o.call(e,n||e)}catch(a){u(a)}}}},p=function(e){if(/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)){return new Blob([String.fromCharCode(65279),e],{type:e.type})}return e},v=function(t,u,d){if(!d){t=p(t)}var v=this,w=t.type,m=w===s,y,h=function(){l(v,"writestart progress write writeend".split(" "))},S=function(){if((f||m&&i)&&e.FileReader){var r=new FileReader;r.onloadend=function(){var t=f?r.result:r.result.replace(/^data:[^;]*;/,"data:attachment/file;");var n=e.open(t,"_blank");if(!n)e.location.href=t;t=undefined;v.readyState=v.DONE;h()};r.readAsDataURL(t);v.readyState=v.INIT;return}if(!y){y=n().createObjectURL(t)}if(m){e.location.href=y}else{var o=e.open(y,"_blank");if(!o){e.location.href=y}}v.readyState=v.DONE;h();c(y)};v.readyState=v.INIT;if(o){y=n().createObjectURL(t);setTimeout(function(){r.href=y;r.download=u;a(r);h();c(y);v.readyState=v.DONE});return}S()},w=v.prototype,m=function(e,t,n){return new v(e,t||e.name||"download",n)};if(typeof navigator!=="undefined"&&navigator.msSaveOrOpenBlob){return function(e,t,n){t=t||e.name||"download";if(!n){e=p(e)}return navigator.msSaveOrOpenBlob(e,t)}}w.abort=function(){};w.readyState=w.INIT=0;w.WRITING=1;w.DONE=2;w.error=w.onwritestart=w.onprogress=w.onwrite=w.onabort=w.onerror=w.onwriteend=null;return m}(typeof self!=="undefined"&&self||typeof window!=="undefined"&&window||this.content);if(typeof module!=="undefined"&&module.exports){module.exports.saveAs=saveAs}else if(typeof define!=="undefined"&&define!==null&&define.amd!==null){define("FileSaver.js",function(){return saveAs})} -------------------------------------------------------------------------------- /script/lib/zlib.js: -------------------------------------------------------------------------------- 1 | /** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */(function() {'use strict';function q(d){throw d;}var t=void 0,v=!0,ca=this;function B(d,a){var c=d.split("."),b=ca;!(c[0]in b)&&b.execScript&&b.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)!c.length&&a!==t?b[e]=a:b=b[e]?b[e]:b[e]={}};var E="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array&&"undefined"!==typeof DataView;function H(d,a){this.index="number"===typeof a?a:0;this.m=0;this.buffer=d instanceof(E?Uint8Array:Array)?d:new (E?Uint8Array:Array)(32768);2*this.buffer.length<=this.index&&q(Error("invalid index"));this.buffer.length<=this.index&&this.f()}H.prototype.f=function(){var d=this.buffer,a,c=d.length,b=new (E?Uint8Array:Array)(c<<1);if(E)b.set(d);else for(a=0;a>>8&255]<<16|J[d>>>16&255]<<8|J[d>>>24&255])>>32-a:J[d]>>8-a);if(8>a+f)g=g<>a-k-1&1,8===++f&&(f=0,b[e++]=J[g],g=0,e===b.length&&(b=this.f()));b[e]=g;this.buffer=b;this.m=f;this.index=e};H.prototype.finish=function(){var d=this.buffer,a=this.index,c;0ea;++ea){for(var M=ea,fa=M,ka=7,M=M>>>1;M;M>>>=1)fa<<=1,fa|=M&1,--ka;da[ea]=(fa<>>0}var J=da;function la(d,a,c){var b,e="number"===typeof a?a:a=0,f="number"===typeof c?c:d.length;b=-1;for(e=f&7;e--;++a)b=b>>>8^S[(b^d[a])&255];for(e=f>>3;e--;a+=8)b=b>>>8^S[(b^d[a])&255],b=b>>>8^S[(b^d[a+1])&255],b=b>>>8^S[(b^d[a+2])&255],b=b>>>8^S[(b^d[a+3])&255],b=b>>>8^S[(b^d[a+4])&255],b=b>>>8^S[(b^d[a+5])&255],b=b>>>8^S[(b^d[a+6])&255],b=b>>>8^S[(b^d[a+7])&255];return(b^4294967295)>>>0} 4 | var ma=[0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759, 5 | 2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977, 6 | 2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755, 7 | 2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956, 8 | 3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270, 9 | 936918E3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117],S=E?new Uint32Array(ma):ma;function T(){}T.prototype.getName=function(){return this.name};T.prototype.getData=function(){return this.data};T.prototype.X=function(){return this.Y};function na(d){this.buffer=new (E?Uint16Array:Array)(2*d);this.length=0}na.prototype.getParent=function(d){return 2*((d-2)/4|0)};na.prototype.push=function(d,a){var c,b,e=this.buffer,f;c=this.length;e[this.length++]=a;for(e[this.length++]=d;0e[b])f=e[c],e[c]=e[b],e[b]=f,f=e[c+1],e[c+1]=e[b+1],e[b+1]=f,c=b;else break;return this.length}; 10 | na.prototype.pop=function(){var d,a,c=this.buffer,b,e,f;a=c[0];d=c[1];this.length-=2;c[0]=c[this.length];c[1]=c[this.length+1];for(f=0;;){e=2*f+2;if(e>=this.length)break;e+2c[e]&&(e+=2);if(c[e]>c[f])b=c[f],c[f]=c[e],c[e]=b,b=c[f+1],c[f+1]=c[e+1],c[e+1]=b;else break;f=e}return{index:d,value:a,length:this.length}};function U(d){var a=d.length,c=0,b=Number.POSITIVE_INFINITY,e,f,g,k,h,m,r,p,l,n;for(p=0;pc&&(c=d[p]),d[p]>=1;n=g<<16|p;for(l=m;lV;V++)switch(v){case 143>=V:ta.push([V+48,8]);break;case 255>=V:ta.push([V-144+400,9]);break;case 279>=V:ta.push([V-256+0,7]);break;case 287>=V:ta.push([V-280+192,8]);break;default:q("invalid literal: "+V)} 12 | oa.prototype.g=function(){var d,a,c,b,e=this.input;switch(this.k){case 0:c=0;for(b=e.length;c>>8&255;l[n++]=m&255;l[n++]=m>>>8&255;if(E)l.set(f,n),n+=f.length,l=l.subarray(0,n);else{r=0;for(p=f.length;rA)for(;0< 15 | A--;)K[I++]=0,Q[0]++;else for(;0A?A:138,G>A-3&&G=G?(K[I++]=17,K[I++]=G-3,Q[17]++):(K[I++]=18,K[I++]=G-11,Q[18]++),A-=G;else if(K[I++]=L[y],Q[L[y]]++,A--,3>A)for(;0A?A:6,G>A-3&&GF;F++)xa[F]=pa[pb[F]];for(aa=19;4=a:return[265,a-11,1];case 14>=a:return[266,a-13,1];case 16>=a:return[267,a-15,1];case 18>=a:return[268,a-17,1];case 22>=a:return[269,a-19,2];case 26>=a:return[270,a-23,2];case 30>=a:return[271,a-27,2];case 34>=a:return[272, 19 | a-31,2];case 42>=a:return[273,a-35,3];case 50>=a:return[274,a-43,3];case 58>=a:return[275,a-51,3];case 66>=a:return[276,a-59,3];case 82>=a:return[277,a-67,4];case 98>=a:return[278,a-83,4];case 114>=a:return[279,a-99,4];case 130>=a:return[280,a-115,4];case 162>=a:return[281,a-131,5];case 194>=a:return[282,a-163,5];case 226>=a:return[283,a-195,5];case 257>=a:return[284,a-227,5];case 258===a:return[285,a-258,0];default:q("invalid length: "+a)}}var a=[],c,b;for(c=3;258>=c;c++)b=d(c),a[c]=b[2]<<24|b[1]<< 20 | 16|b[0];return a}(),Ba=E?new Uint32Array(za):za; 21 | function ua(d,a){function c(a,c){var b=a.P,d=[],e=0,f;f=Ba[a.length];d[e++]=f&65535;d[e++]=f>>16&255;d[e++]=f>>24;var g;switch(v){case 1===b:g=[0,b-1,0];break;case 2===b:g=[1,b-2,0];break;case 3===b:g=[2,b-3,0];break;case 4===b:g=[3,b-4,0];break;case 6>=b:g=[4,b-5,1];break;case 8>=b:g=[5,b-7,1];break;case 12>=b:g=[6,b-9,2];break;case 16>=b:g=[7,b-13,2];break;case 24>=b:g=[8,b-17,3];break;case 32>=b:g=[9,b-25,3];break;case 48>=b:g=[10,b-33,4];break;case 64>=b:g=[11,b-49,4];break;case 96>=b:g=[12,b- 22 | 65,5];break;case 128>=b:g=[13,b-97,5];break;case 192>=b:g=[14,b-129,6];break;case 256>=b:g=[15,b-193,6];break;case 384>=b:g=[16,b-257,7];break;case 512>=b:g=[17,b-385,7];break;case 768>=b:g=[18,b-513,8];break;case 1024>=b:g=[19,b-769,8];break;case 1536>=b:g=[20,b-1025,9];break;case 2048>=b:g=[21,b-1537,9];break;case 3072>=b:g=[22,b-2049,10];break;case 4096>=b:g=[23,b-3073,10];break;case 6144>=b:g=[24,b-4097,11];break;case 8192>=b:g=[25,b-6145,11];break;case 12288>=b:g=[26,b-8193,12];break;case 16384>= 23 | b:g=[27,b-12289,12];break;case 24576>=b:g=[28,b-16385,13];break;case 32768>=b:g=[29,b-24577,13];break;default:q("invalid distance")}f=g;d[e++]=f[0];d[e++]=f[1];d[e++]=f[2];var h,k;h=0;for(k=d.length;h=f;)u[f++]=0;for(f=0;29>=f;)w[f++]=0}u[256]=1;b=0;for(e=a.length;b=e){p&&c(p,-1);f=0;for(g=e-b;fg&&a+gf&&(e=b,f=g);if(258===g)break}return new ya(f,a-e)} 26 | function va(d,a){var c=d.length,b=new na(572),e=new (E?Uint8Array:Array)(c),f,g,k,h,m;if(!E)for(h=0;h2*e[n-1]+f[n]&&(e[n]=2*e[n-1]+f[n]),k[n]=Array(e[n]),h[n]=Array(e[n]);for(l=0;ld[l]?(k[n][s]=u,h[n][s]=a,w+=2):(k[n][s]=d[l],h[n][s]=l,++l);m[n]=0;1===f[n]&&b(n)}return g} 29 | function wa(d){var a=new (E?Uint16Array:Array)(d.length),c=[],b=[],e=0,f,g,k,h;f=0;for(g=d.length;f>>=1}return a};function Ea(d,a){this.input=d;this.b=this.c=0;this.i={};a&&(a.flags&&(this.i=a.flags),"string"===typeof a.filename&&(this.filename=a.filename),"string"===typeof a.comment&&(this.A=a.comment),a.deflateOptions&&(this.l=a.deflateOptions));this.l||(this.l={})} 30 | Ea.prototype.g=function(){var d,a,c,b,e,f,g,k,h=new (E?Uint8Array:Array)(32768),m=0,r=this.input,p=this.c,l=this.filename,n=this.A;h[m++]=31;h[m++]=139;h[m++]=8;d=0;this.i.fname&&(d|=Fa);this.i.fcomment&&(d|=Ga);this.i.fhcrc&&(d|=Ha);h[m++]=d;a=(Date.now?Date.now():+new Date)/1E3|0;h[m++]=a&255;h[m++]=a>>>8&255;h[m++]=a>>>16&255;h[m++]=a>>>24&255;h[m++]=0;h[m++]=Ia;if(this.i.fname!==t){g=0;for(k=l.length;g>>8&255),h[m++]=f&255;h[m++]=0}if(this.i.comment){g= 31 | 0;for(k=n.length;g>>8&255),h[m++]=f&255;h[m++]=0}this.i.fhcrc&&(c=la(h,0,m)&65535,h[m++]=c&255,h[m++]=c>>>8&255);this.l.outputBuffer=h;this.l.outputIndex=m;e=new oa(r,this.l);h=e.g();m=e.b;E&&(m+8>h.buffer.byteLength?(this.a=new Uint8Array(m+8),this.a.set(new Uint8Array(h.buffer)),h=this.a):h=new Uint8Array(h.buffer));b=la(r,t,t);h[m++]=b&255;h[m++]=b>>>8&255;h[m++]=b>>>16&255;h[m++]=b>>>24&255;k=r.length;h[m++]=k&255;h[m++]=k>>>8&255;h[m++]=k>>>16&255;h[m++]= 32 | k>>>24&255;this.c=p;E&&m>>=1;switch(d){case 0:var a=this.input,c=this.c,b=this.a,e=this.b,f=a.length,g=t,k=t,h=b.length,m=t;this.e=this.j=0;c+1>=f&&q(Error("invalid uncompressed block header: LEN"));g=a[c++]|a[c++]<<8;c+1>=f&&q(Error("invalid uncompressed block header: NLEN"));k=a[c++]|a[c++]<<8;g===~k&&q(Error("invalid uncompressed block header: length verify"));c+g>a.length&&q(Error("input buffer is broken"));switch(this.r){case Ka:for(;e+g>b.length;){m= 35 | h-e;g-=m;if(E)b.set(a.subarray(c,c+m),e),e+=m,c+=m;else for(;m--;)b[e++]=a[c++];this.b=e;b=this.f();e=this.b}break;case Ja:for(;e+g>b.length;)b=this.f({F:2});break;default:q(Error("invalid inflate mode"))}if(E)b.set(a.subarray(c,c+g),e),e+=g,c+=g;else for(;g--;)b[e++]=a[c++];this.c=c;this.b=e;this.a=b;break;case 1:this.s(Za,$a);break;case 2:for(var r=X(this,5)+257,p=X(this,5)+1,l=X(this,4)+4,n=new (E?Uint8Array:Array)(ab.length),s=t,u=t,w=t,C=t,x=t,D=t,N=t,z=t,O=t,z=0;z=Y?8:255>=Y?9:279>=Y?7:8;var Za=U(lb),nb=new (E?Uint8Array:Array)(30),ob,qb;ob=0;for(qb=nb.length;ob=g&&q(Error("input buffer is broken")),c|=e[f++]<>>a;d.e=b-a;d.c=f;return k} 39 | function bb(d,a){for(var c=d.j,b=d.e,e=d.input,f=d.c,g=e.length,k=a[0],h=a[1],m,r;b=g);)c|=e[f++]<>>16;r>b&&q(Error("invalid code length: "+r));d.j=c>>r;d.e=b-r;d.c=f;return m&65535} 40 | W.prototype.s=function(d,a){var c=this.a,b=this.b;this.C=d;for(var e=c.length-258,f,g,k,h;256!==(f=bb(this,d));)if(256>f)b>=e&&(this.b=b,c=this.f(),b=this.b),c[b++]=f;else{g=f-257;h=eb[g];0=e&&(this.b=b,c=this.f(),b=this.b);for(;h--;)c[b]=c[b++-k]}for(;8<=this.e;)this.e-=8,this.c--;this.b=b}; 41 | W.prototype.S=function(d,a){var c=this.a,b=this.b;this.C=d;for(var e=c.length,f,g,k,h;256!==(f=bb(this,d));)if(256>f)b>=e&&(c=this.f(),e=c.length),c[b++]=f;else{g=f-257;h=eb[g];0e&&(c=this.f(),e=c.length);for(;h--;)c[b]=c[b++-k]}for(;8<=this.e;)this.e-=8,this.c--;this.b=b}; 42 | W.prototype.f=function(){var d=new (E?Uint8Array:Array)(this.b-32768),a=this.b-32768,c,b,e=this.a;if(E)d.set(e.subarray(32768,d.length));else{c=0;for(b=d.length;cc;++c)e[c]=e[a+c];this.b=32768;return e}; 43 | W.prototype.T=function(d){var a,c=this.input.length/this.c+1|0,b,e,f,g=this.input,k=this.a;d&&("number"===typeof d.F&&(c=d.F),"number"===typeof d.O&&(c+=d.O));2>c?(b=(g.length-this.c)/this.C[2],f=258*(b/2)|0,e=fa&&(this.a.length=a),d=this.a);return this.buffer=d};function rb(d){this.input=d;this.c=0;this.t=[];this.D=!1}rb.prototype.W=function(){this.D||this.h();return this.t.slice()}; 46 | rb.prototype.h=function(){for(var d=this.input.length;this.c>>0;la(e,t,t)!==r&&q(Error("invalid CRC-32 checksum: 0x"+la(e,t,t).toString(16)+ 48 | " / 0x"+r.toString(16)));a.ca=c=(p[l++]|p[l++]<<8|p[l++]<<16|p[l++]<<24)>>>0;(e.length&4294967295)!==c&&q(Error("invalid input size: "+(e.length&4294967295)+" / "+c));this.t.push(a);this.c=l}this.D=v;var n=this.t,s,u,w=0,C=0,x;s=0;for(u=n.length;s>>0;d=a}for(var e=1,f=0,g=d.length,k,h=0;0>>0};function tb(d,a){var c,b;this.input=d;this.c=0;if(a||!(a={}))a.index&&(this.c=a.index),a.verify&&(this.Z=a.verify);c=d[this.c++];b=d[this.c++];switch(c&15){case ub:this.method=ub;break;default:q(Error("unsupported compression method"))}0!==((c<<8)+b)%31&&q(Error("invalid fcheck flag:"+((c<<8)+b)%31));b&32&&q(Error("fdict flag is not supported"));this.K=new W(d,{index:this.c,bufferSize:a.bufferSize,bufferType:a.bufferType,resize:a.resize})} 49 | tb.prototype.h=function(){var d=this.input,a,c;a=this.K.h();this.c=this.K.c;this.Z&&(c=(d[this.c++]<<24|d[this.c++]<<16|d[this.c++]<<8|d[this.c++])>>>0,c!==sb(a)&&q(Error("invalid adler-32 checksum")));return a};var ub=8;function vb(d,a){this.input=d;this.a=new (E?Uint8Array:Array)(32768);this.k=Z.o;var c={},b;if((a||!(a={}))&&"number"===typeof a.compressionType)this.k=a.compressionType;for(b in a)c[b]=a[b];c.outputBuffer=this.a;this.J=new oa(this.input,c)}var Z=sa; 50 | vb.prototype.g=function(){var d,a,c,b,e,f,g,k=0;g=this.a;d=ub;switch(d){case ub:a=Math.LOG2E*Math.log(32768)-8;break;default:q(Error("invalid compression method"))}c=a<<4|d;g[k++]=c;switch(d){case ub:switch(this.k){case Z.NONE:e=0;break;case Z.v:e=1;break;case Z.o:e=2;break;default:q(Error("unsupported compression type"))}break;default:q(Error("invalid compression method"))}b=e<<6|0;g[k++]=b|31-(256*c+b)%31;f=sb(this.input);this.J.b=k;g=this.J.g();k=g.length;E&&(g=new Uint8Array(g.buffer),g.length<= 51 | k+4&&(this.a=new Uint8Array(g.length+4),this.a.set(g),g=this.a),g=g.subarray(0,k+4));g[k++]=f>>24&255;g[k++]=f>>16&255;g[k++]=f>>8&255;g[k++]=f&255;return g};function wb(d,a){var c,b,e,f;if(Object.keys)c=Object.keys(a);else for(b in c=[],e=0,a)c[e++]=b;e=0;for(f=c.length;e 0){ 69 | fileType = url.split(".").pop().toUpperCase(); 70 | } 71 | el("disktype").innerText = fileType + " file"; 72 | }); 73 | }; 74 | 75 | me.browseLocalFile = function(){ 76 | var input = document.createElement('input'); 77 | input.type = 'file'; 78 | input.onchange = function(e){ 79 | console.log("file uploaded"); 80 | var files = e.target.files; 81 | if (files.length){ 82 | var file = files[0]; 83 | 84 | var reader = new FileReader(); 85 | reader.onload = function(){ 86 | me.load(reader.result); 87 | }; 88 | reader.onerror = function(){ 89 | console.error("Failed to read file!",reader.error); 90 | el("feedback").innerHTML = "Sorry, something went wrong reading this file."; 91 | el("feedback").style.display = "block"; 92 | reader.abort(); 93 | }; 94 | reader.readAsArrayBuffer(file); 95 | } 96 | }; 97 | input.click(); 98 | } 99 | 100 | function listFolder(folder){ 101 | 102 | currentFolder = folder; 103 | 104 | var container = el("list"); 105 | container.innerHTML = ""; 106 | 107 | var path = adf.getInfo().label; 108 | if (folder.parent){ 109 | container.appendChild(createListItem({ 110 | sector: folder.parent, 111 | name: "..", 112 | typeString: "DIR" 113 | })); 114 | path += "/" + folder.name; 115 | } 116 | 117 | el("disklabel").innerHTML = path; 118 | 119 | 120 | function sortByName(a,b) { 121 | if (a.name < b.name) 122 | return -1; 123 | if (a.name > b.name) 124 | return 1; 125 | return 0; 126 | } 127 | folder.folders.sort(sortByName); 128 | folder.files.sort(sortByName); 129 | 130 | 131 | folder.folders.forEach(function(f){ 132 | container.appendChild(createListItem(f)); 133 | }); 134 | 135 | folder.files.forEach(function(f){ 136 | container.appendChild(createListItem(f)); 137 | }); 138 | 139 | showInfo(folder); 140 | } 141 | 142 | function refreshFolder(){ 143 | if (currentFolder){ 144 | var dir = adf.readFolderAtSector(currentFolder.sector); 145 | listFolder(dir); 146 | } 147 | } 148 | 149 | function createListItem(f){ 150 | var item = document.createElement("div"); 151 | item.className = "listitem " + f.typeString; 152 | 153 | var icon = document.createElement("i"); 154 | icon.className = "fa fa-folder"; 155 | 156 | var label = document.createElement("span"); 157 | label.className = "label"; 158 | label.innerHTML = f.name; 159 | 160 | var size; 161 | if (f.typeString == "FILE"){ 162 | icon.className = "fa fa-file-o"; 163 | 164 | size = document.createElement("span"); 165 | size.className = "size"; 166 | size.innerHTML = formatSize(f.size); 167 | } 168 | 169 | item.onclick = function(){ 170 | if (f.typeString == "FILE"){ 171 | showInfo(f); 172 | }else{ 173 | var dir = adf.readFolderAtSector(f.sector); 174 | listFolder(dir); 175 | } 176 | 177 | }; 178 | 179 | item.appendChild(icon); 180 | item.appendChild(label); 181 | if (size) item.appendChild(size); 182 | 183 | return item; 184 | } 185 | 186 | function showInfo(f){ 187 | var container = el("fileinfo"); 188 | 189 | var content = ""; 190 | content += '

' + f.name + '

'; 191 | content += ""; 192 | 193 | if (f.size) content += ""; 194 | if (f.comment) content += ""; 195 | if (f.lastChangeDays && f.lastChangeDays>1000){ 196 | content += ""; 197 | } 198 | 199 | content += "
Type:" + f.typeString + "
Size:" + formatSize(f.size) + "
Comment:" + f.comment + "
LastChanged:" + formatDateTime(f.lastChangeDays,f.lastChangeMinutes,f.lastChangeTicks) + "
"; 200 | 201 | 202 | if (f.typeString == "FILE"){ 203 | currentFile=f; 204 | content += "

Actions

"; 205 | content += '
Show as text
'; 206 | content += '
Show as hex
'; 207 | content += '
Download
'; 208 | content += '
Delete file
'; 209 | content += '
Rename file
'; 210 | content += '
'; 211 | } 212 | 213 | content += "

Folder

"; 214 | content += '
Upload file
'; 215 | content += '
Create folder
'; 216 | 217 | if (currentFolder.sector !== 880){ 218 | content += '
Delete folder
'; 219 | content += '
Rename folder
'; 220 | } 221 | 222 | 223 | content += "
"; 224 | container.innerHTML = content; 225 | 226 | if (f.typeString == "FILE"){ 227 | var fileType = AdfViewer.detectFileType(f.sector); 228 | 229 | if (fileType){ 230 | container = el("filetypeactions"); 231 | var info = fileType.name; 232 | if (fileType.info) info += "
" + fileType.info; 233 | var intro = "This is a"; 234 | if (["a","e","i","o","u"].indexOf(info.substr(0,1).toLowerCase())>=0) intro+="n"; 235 | 236 | container.innerHTML = intro + " " + info; 237 | if (fileType.actions){ 238 | fileType.actions.forEach(function(action){ 239 | var div = document.createElement("div"); 240 | div.innerHTML = action; 241 | div.className = "action"; 242 | div.onclick = function(){fileType.handler.handle(fileType.file,action)}; 243 | container.appendChild(div); 244 | }); 245 | } 246 | } 247 | } 248 | } 249 | 250 | function updateFreeSize(){ 251 | let sizes = adf.getFreeSize(); 252 | let free = formatDiskSize(sizes.free); 253 | let used = formatDiskSize(sizes.used); 254 | el("diskspace").innerHTML = "Used: " + used + ", Free: " + free; 255 | } 256 | 257 | function el(id){ 258 | return document.getElementById(id); 259 | } 260 | 261 | function formatSize(size){ 262 | let n = "bytes"; 263 | if (size >= 1024){ 264 | size = Math.round(size / 1024); 265 | n = "kb"; 266 | if (size >= 1024){ 267 | size = Math.round(size / 1024); 268 | n = "mb"; 269 | if (size >= 1024){ 270 | size = Math.round(size / 1024); 271 | n = "gb"; 272 | } 273 | } 274 | } 275 | if (size === 0) size = 1; 276 | return size + " " + n; 277 | } 278 | 279 | function formatDiskSize(size){ 280 | let s = formatSize(size).split(" "); 281 | return "" + s[0] + " " + s[1]; 282 | } 283 | 284 | function formatDateTime(days,minutes,ticks){ 285 | var start = 252457200000; // 1 jan 1978; 286 | var monthNames = ["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"]; 287 | 288 | // ticks = 50 ticks a second 289 | var d = new Date(start + (days * 86400000) + (minutes * 3600000) + (ticks * 50000)); 290 | var m = d.getMinutes(); 291 | var h = d.getHours(); 292 | if (m<10) m = "0" + m; 293 | if (h<10) m = "0" + h; 294 | return d.getDate() + " " + monthNames[d.getMonth()] + " " + d.getFullYear() + " " + h + ":" + m; 295 | } 296 | 297 | me.showAscii = function(sector){ 298 | showFile(sector,true); 299 | }; 300 | 301 | me.showHex = function(sector){ 302 | showFile(sector,false); 303 | }; 304 | 305 | me.showImage = function(image){ 306 | showImage(image); 307 | }; 308 | 309 | me.detectFileType = function(sector){ 310 | var file = adf.readFileAtSector(sector,true); 311 | return FileType.detect(file.content); 312 | }; 313 | 314 | function showFile(sector,asAscii){ 315 | currentSector = sector; 316 | var file = adf.readFileAtSector(sector,true); 317 | 318 | el("filelabel").innerHTML = file.name; 319 | 320 | el("file").style.display = "block"; 321 | el("folder").style.display = "none"; 322 | el("canvas").className = "hidden"; 323 | 324 | var hex = el("hex"); 325 | var ascii = el("ascii"); 326 | hex.className = asAscii ? "ascii" : "hex"; 327 | ascii.className = asAscii ? "ascii" : "hex"; 328 | 329 | var s = ""; 330 | var a = ""; 331 | 332 | for (var i = 1; i<= file.size; i++){ 333 | var eol = ""; 334 | if (i%16 == 0) eol = "\n"; 335 | var b = file.content[i-1]; 336 | s += formatHex(b) + " " + eol; 337 | a += String.fromCharCode(b); 338 | if (!asAscii) (a += " " + eol); 339 | } 340 | 341 | hex.value = s; 342 | ascii.value = a; 343 | } 344 | 345 | function showImage(image){ 346 | el("filelabel").innerHTML = currentFile.name; 347 | 348 | el("file").style.display = "block"; 349 | el("folder").style.display = "none"; 350 | el("hex").className = "hidden"; 351 | el("ascii").className = "hidden"; 352 | 353 | if (image){ 354 | var canvas = el("canvas"); 355 | var ctx = canvas.getContext("2d"); 356 | ctx.fillStyle = "black"; 357 | ctx.fillRect(0,0,canvas.width,canvas.height); 358 | el("canvas").className = ""; 359 | 360 | var w = canvas.width; 361 | var h = w * (image.height/image.width); 362 | 363 | if (h>canvas.height){ 364 | h = canvas.height; 365 | w = h * (image.width/image.height); 366 | } 367 | var x = (canvas.width - w)>>1; 368 | var y = (canvas.height - h)>>1; 369 | 370 | ctx.imageSmoothingEnabled= false; 371 | ctx.drawImage(image,x,y,w,h); 372 | } 373 | } 374 | 375 | 376 | me.showFolder = function(){ 377 | el("file").style.display = "none"; 378 | el("folder").style.display = "block"; 379 | el("raw").style.display = "none"; 380 | }; 381 | 382 | me.showRoot = function(){ 383 | listFolder(adf.readRootFolder()); 384 | 385 | var disk = adf.getDisk(); 386 | var container = el("fileinfo"); 387 | container.innerHTML += "" ; 388 | 389 | el("filemanager").classList.add("disk"); 390 | 391 | var diskspace = el("diskspace"); 392 | 393 | let free = formatDiskSize(disk.free); 394 | let used = formatDiskSize(disk.used); 395 | diskspace.innerHTML = "Used: " + used + ", Free: " + free; 396 | }; 397 | 398 | me.download = function(sector){ 399 | sector = sector || currentSector; 400 | var file = adf.readFileAtSector(sector,true); 401 | 402 | 403 | var b = new Blob([file.content], {type: "application/octet-stream"}); 404 | 405 | var fileName = file.name; 406 | saveAs(b,fileName); 407 | }; 408 | 409 | me.delete = function(sector){ 410 | sector = sector || currentSector; 411 | adf.deleteFileAtSector(sector,true); 412 | updateFreeSize(); 413 | refreshFolder(); 414 | }; 415 | 416 | me.rename = function(sector,type){ 417 | 418 | if (!sector && type === TYPE_FOLDER) sector = currentFolder.sector; 419 | sector = sector || currentSector; 420 | 421 | var name = adf.readHeaderBlock(sector).name; 422 | 423 | me.showDialog({ 424 | title:"Rename " + (type === TYPE_FILE ? "file":"folder"), 425 | message:"Please enter the new name", 426 | inputValue: name, 427 | callback:function(confirm){ 428 | if (confirm){ 429 | var value = document.getElementById("dialoginput").value; 430 | if (value){ 431 | adf.renameFileOrFolderAtSector(sector,value); 432 | refreshFolder(); 433 | } 434 | } 435 | } 436 | }); 437 | }; 438 | 439 | me.upload = function(){ 440 | var input = document.createElement('input'); 441 | input.type = 'file'; 442 | input.onchange = function(e){ 443 | console.log("file uploaded"); 444 | var files = e.target.files; 445 | if (files.length){ 446 | var file = files[0]; 447 | 448 | var reader = new FileReader(); 449 | reader.onload = function(){ 450 | let sector = adf.writeFile(file.name,reader.result,currentFolder.sector); 451 | if (!sector){ 452 | alert("Sorry, not enough space on this disk."); 453 | return; 454 | } 455 | console.log("File written to sector",sector); 456 | updateFreeSize(); 457 | refreshFolder(); 458 | }; 459 | reader.readAsArrayBuffer(file); 460 | } 461 | }; 462 | input.click(); 463 | }; 464 | 465 | me.createFolder = function(){ 466 | 467 | me.showDialog({ 468 | title:"Create New Folder" , 469 | message:"Please enter the name of the new folder", 470 | inputValue: "new folder", 471 | callback:function(confirm){ 472 | if (confirm){ 473 | var value = document.getElementById("dialoginput").value; 474 | if (value){ 475 | adf.createFolder(value,currentFolder.sector); 476 | updateFreeSize(); 477 | refreshFolder(); 478 | } 479 | } 480 | } 481 | }); 482 | }; 483 | 484 | me.deleteFolder = function(){ 485 | var deleted = adf.deleteFolderAtSector(currentFolder.sector); 486 | if (deleted){ 487 | var up = document.getElementById("list").querySelectorAll(".DIR")[0]; 488 | if (up) up.click(); 489 | updateFreeSize(); 490 | }else{ 491 | alert("can't delete folder, it's not empty"); 492 | } 493 | }; 494 | 495 | me.showSector = function(sector){ 496 | currentSector = sector || 0; 497 | let disk = adf.getDisk(); 498 | 499 | if (isNaN(currentSector)) currentSector = 0; 500 | if (currentSector<0) currentSector=0; 501 | if (currentSector>=disk.sectorCount) currentSector = disk.sectorCount-1; 502 | 503 | el("sector").value = currentSector; 504 | el("sectorinfo").innerHTML = adf.getSectorType(sector); 505 | 506 | el("file").style.display = "none"; 507 | el("folder").style.display = "none"; 508 | el("raw").style.display = "block"; 509 | 510 | var content = adf.readSector(currentSector); 511 | 512 | var hex = el("sectorhex"); 513 | var ascii = el("sectorascii"); 514 | 515 | var s = ""; 516 | var a = ""; 517 | 518 | for (var i = 1; i<= content.length; i++){ 519 | var eol = ""; 520 | if (i%16 == 0) eol = "\n"; 521 | var b = content[i-1]; 522 | s += formatHex(b) + " " + eol; 523 | a += String.fromCharCode(b) + " " + eol; 524 | } 525 | 526 | hex.value = s; 527 | ascii.value = a; 528 | 529 | }; 530 | 531 | me.nextSector = function(){ 532 | me.showSector(++currentSector); 533 | }; 534 | me.prevSector = function(){ 535 | me.showSector(--currentSector); 536 | }; 537 | me.onSectorUpdate = function(){ 538 | var value = el("sector").value; 539 | if (isNaN(value)) value = 0; 540 | if (value != currentSector) me.showSector(value); 541 | }; 542 | 543 | me.handleDragEnter = function(e){ 544 | e.stopPropagation(); 545 | e.preventDefault(); 546 | el("dropzone").className = "over"; 547 | }; 548 | 549 | me.handleDragOver = function(e){ 550 | e.stopPropagation(); 551 | e.preventDefault(); 552 | }; 553 | 554 | me.handleDragLeave = function(e){ 555 | e.stopPropagation(); 556 | e.preventDefault(); 557 | el("dropzone").className = ""; 558 | } 559 | 560 | me.handleDrop = function(e){ 561 | e.stopPropagation(); 562 | e.preventDefault(); 563 | el("dropzone").className = ""; 564 | 565 | var dt = e.dataTransfer; 566 | var files = dt.files; 567 | 568 | if (files.length){ 569 | var file = files[0]; 570 | 571 | var reader = new FileReader(); 572 | reader.onload = function(){ 573 | me.load(reader.result); 574 | }; 575 | reader.onerror = function(){ 576 | console.error("Failed to read file!",reader.error); 577 | el("feedback").innerHTML = "Sorry, something went wrong reading this file."; 578 | el("feedback").style.display = "block"; 579 | reader.abort(); 580 | }; 581 | reader.readAsArrayBuffer(file); 582 | } 583 | }; 584 | 585 | me.dialog = function(confirm){ 586 | if (dialogFunction) dialogFunction(confirm); 587 | dialogFunction = false; 588 | 589 | var dialog=document.getElementById("modaldialog"); 590 | dialog.className = ""; 591 | }; 592 | 593 | me.showDialog = function(config){ 594 | var dialog=document.getElementById("modaldialog"); 595 | document.getElementById("dialogtitle").innerHTML = config.title || "Please confirm"; 596 | document.getElementById("dialogcontent").innerHTML = config.message || ""; 597 | document.getElementById("dialoginput").value = config.inputValue || ""; 598 | dialogFunction = config.callback; 599 | dialog.className = "active"; 600 | }; 601 | 602 | function formatHex(nr){ 603 | var result = nr.toString(16).toUpperCase(); 604 | if (result.length<2) result = "0" + result; 605 | return result; 606 | } 607 | 608 | return me; 609 | }(); 610 | 611 | 612 | 613 | function getUrlParameter(param){ 614 | if (window.location.getParameter){ 615 | return window.location.getParameter(param); 616 | } else if (location.search) { 617 | var parts = location.search.substring(1).split('&'); 618 | for (var i = 0; i < parts.length; i++) { 619 | var nv = parts[i].split('='); 620 | if (!nv[0]) continue; 621 | if (nv[0] == param) { 622 | return nv[1] || true; 623 | } 624 | } 625 | } 626 | } 627 | 628 | function loadScript(url,next){ 629 | var s = document.createElement('script'); 630 | s.type = 'application/javascript'; 631 | s.src = url; 632 | s.addEventListener('error', function(){ 633 | console.error("Failed loading script " + url); 634 | }, false); 635 | s.addEventListener('load', function(){ 636 | if (next) next(); 637 | }, false); 638 | document.getElementsByTagName('head')[0].appendChild(s); 639 | } 640 | -------------------------------------------------------------------------------- /style/main.css: -------------------------------------------------------------------------------- 1 | html,body{ 2 | margin: 0; 3 | padding: 0; 4 | font-family: Helvetica, Arial, sans-serif; 5 | font-size: 14px; 6 | box-sizing: border-box; 7 | } 8 | 9 | *, *:before, *:after { 10 | box-sizing: inherit; 11 | } 12 | 13 | .clear{ 14 | clear: both; 15 | } 16 | 17 | .hidden{ 18 | display: none; 19 | } 20 | 21 | #container{ 22 | width: 800px; 23 | margin: auto; 24 | } 25 | 26 | textarea{ 27 | font-family: "Courier New",monospace; 28 | font-size: 13px; 29 | } 30 | 31 | #dropzone{ 32 | border: 1px dashed #427fb7; 33 | margin: 10px 0; 34 | padding: 10px; 35 | } 36 | 37 | #dropzone.over{ 38 | border: 1px dashed #fb9b00; 39 | box-shadow: 0 0 10px rgba(251, 155, 0, 0.5); 40 | } 41 | 42 | #dropzone.over .selector{ 43 | pointer-events: none; 44 | } 45 | 46 | #dropzone .selector{ 47 | float: right; 48 | } 49 | 50 | #filemanager{ 51 | position: relative; 52 | } 53 | 54 | #filemanager .panel{ 55 | border: 1px solid silver; 56 | } 57 | 58 | .caption{ 59 | background-color: #427fb7; 60 | color: white; 61 | padding: 4px; 62 | } 63 | 64 | .caption.amiga{ 65 | background-image: url("../img/amiga.svg"); 66 | background-size: 20px 16px; 67 | background-position: 2px 4px; 68 | background-repeat: no-repeat; 69 | 70 | padding: 4px 4px 4px 24px; 71 | } 72 | 73 | #filemanager.disk .caption .diskmenu{ 74 | display: initial; 75 | } 76 | 77 | .caption .diskmenu{ 78 | float: right; 79 | color: rgba(255, 255, 255, 0.7); 80 | padding-right: 4px; 81 | display: none; 82 | } 83 | 84 | .caption .diskmenu b{ 85 | color: white; 86 | font-weight: normal; 87 | } 88 | 89 | .caption .diskmenu .fa-download{ 90 | padding-left: 10px; 91 | } 92 | 93 | .caption .diskmenu .fa-download:hover{ 94 | color: white; 95 | cursor: pointer; 96 | } 97 | 98 | .diskheader{ 99 | position: relative; 100 | border-bottom: 1px solid silver; 101 | min-height: 24px; 102 | } 103 | 104 | .diskheader .button{ 105 | display: inline-block; 106 | position: absolute; 107 | padding: 4px; 108 | background-color: #c0d2dc; 109 | } 110 | 111 | .diskheader .button:hover{ 112 | cursor: pointer; 113 | background-color: #d5e8f2; 114 | } 115 | 116 | .diskheader .itemlabel{ 117 | padding: 4px 4px 4px 44px; 118 | min-height: 24px; 119 | } 120 | 121 | .diskheader .button.right{ 122 | right: 0; 123 | } 124 | 125 | .diskheader .inline, 126 | .diskheader .button.inline{ 127 | display: inline-block; 128 | padding: 2px 4px; 129 | position: relative; 130 | } 131 | 132 | .diskheader input{ 133 | width: 50px; 134 | text-align: center; 135 | border: 0; 136 | display: inline-block; 137 | } 138 | 139 | #list, 140 | #hex, 141 | #sectorhex{ 142 | height: 400px; 143 | width: 500px; 144 | overflow: scroll; 145 | position: absolute; 146 | } 147 | 148 | 149 | #fileinfo, 150 | #ascii, 151 | #sectorascii{ 152 | width: 300px; 153 | height: 400px; 154 | float: right; 155 | background-color: #f8f8f8; 156 | border-left: 1px solid silver; 157 | padding: 4px; 158 | font-size: 12px; 159 | } 160 | 161 | #hex.ascii{ 162 | display: none; 163 | } 164 | #ascii.ascii{ 165 | width: 800px; 166 | } 167 | 168 | #fileinfo h3{ 169 | margin: 0; 170 | padding: 0; 171 | font-size: 14px; 172 | } 173 | 174 | #fileinfo h4{ 175 | margin: 10px 0 4px 0; 176 | padding: 0 0 2px 0; 177 | font-size: 12px; 178 | border-bottom: 1px solid silver; 179 | } 180 | 181 | #fileinfo .info{ 182 | padding: 4px 4px 4px 20px; 183 | } 184 | 185 | #fileinfo td{ 186 | font-size: 12px; 187 | border-bottom: 1px solid silver; 188 | } 189 | 190 | #fileinfo .action{ 191 | padding: 2px 0; 192 | color: #427fb7; 193 | } 194 | 195 | #fileinfo .action:hover{ 196 | cursor: pointer; 197 | color: #079bd7; 198 | text-decoration: underline; 199 | } 200 | 201 | .listitem{ 202 | padding: 4px 8px; 203 | border-bottom: 1px solid silver; 204 | } 205 | 206 | .listitem i{ 207 | display: inline-block; 208 | width: 20px; 209 | color: #427fb7; 210 | } 211 | 212 | .listitem.DIR i{ 213 | color: #dcc200; 214 | } 215 | 216 | .listitem .label{ 217 | display: inline-block; 218 | width: 200px; 219 | } 220 | 221 | .listitem.DIR{ 222 | background-color: #F5f5f5; 223 | } 224 | 225 | .listitem:hover{ 226 | cursor: pointer; 227 | border-bottom: 1px solid #485f74; 228 | background-color: #deebf5; 229 | } 230 | 231 | #feedback{ 232 | border: 1px dashed #ff7405; 233 | margin: 10px 0; 234 | padding: 10px; 235 | } 236 | 237 | .footer{ 238 | margin-top: 20px; 239 | text-align: center; 240 | font-size: 12px; 241 | color: #427fb7; 242 | } 243 | 244 | .footer a{ 245 | color: #427fb7; 246 | text-decoration: underline; 247 | } 248 | 249 | #feedback, 250 | #folder, 251 | #file, 252 | #raw{ 253 | display: none; 254 | } 255 | 256 | #filetypeactions{ 257 | padding: 4px 0; 258 | margin: 4px 0; 259 | border-top: 1px solid rgba(0, 0, 0, 0.15); 260 | } 261 | 262 | #filetypeactions .action{ 263 | text-transform: capitalize; 264 | } 265 | 266 | 267 | #filemanager #modaldialog{ 268 | position: absolute; 269 | left: 0; 270 | top: 0; 271 | bottom: 0; 272 | right: 0; 273 | background-color: rgba(0, 0, 0, 0.2); 274 | display: none; 275 | z-index: 1000; 276 | } 277 | 278 | #filemanager #modaldialog.active{ 279 | display: block; 280 | } 281 | 282 | #filemanager #modaldialog .dialog{ 283 | margin: 20px auto; 284 | border: 1px solid silver; 285 | box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.2); 286 | width: 300px; 287 | max-width: 100%; 288 | } 289 | 290 | #filemanager #modaldialog .dialog #dialogtitle{ 291 | background-color: #e8e8e8; 292 | padding: 4px; 293 | font-size: 14px; 294 | margin: 0; 295 | } 296 | 297 | #filemanager #modaldialog .dialog .content{ 298 | background-color: #fafafa; 299 | padding: 20px; 300 | min-height: 100px; 301 | } 302 | 303 | #filemanager #modaldialog .dialog .inputbox{ 304 | width: 100%; 305 | padding: 8px; 306 | border: 1px solid silver; 307 | text-align: center; 308 | margin-top: 10px; 309 | } 310 | 311 | #filemanager #modaldialog .dialog .buttons{ 312 | text-align: center; 313 | padding: 8px; 314 | background-color: #f6f6f6; 315 | } 316 | 317 | #filemanager #modaldialog .dialog .buttons .btn{ 318 | border: 1px solid silver; 319 | text-align: center; 320 | padding: 10px 20px; 321 | background-color: #eeeeee; 322 | margin: 2px 12px; 323 | display: inline-block; 324 | min-width: 100px; 325 | } 326 | 327 | #filemanager #modaldialog .dialog .buttons .btn:hover{ 328 | background-color: white; 329 | cursor: pointer; 330 | } 331 | 332 | 333 | -------------------------------------------------------------------------------- /tosec/amiga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steffest/ADF-reader-writer/f60b0167bc5a99fbc71cef387f811135cf9aec58/tosec/amiga.png -------------------------------------------------------------------------------- /tosec/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | Drop your .adf files here 18 |
19 | 20 |
21 |
22 | 23 |
24 |
25 | 26 |
27 |
x
ADF file
28 |
29 |
30 |
Read Raw sectors
31 |
Disk:
32 |
 
33 |
34 |
35 | 36 |
37 |
38 | 39 |
40 |
41 |
42 | 43 |
44 |
45 |
Back
46 |
File:
47 |
 
48 |
49 | 52 | 55 |
56 |
57 | 58 |
59 |
60 |
Back
61 | Sector: 62 |
<
63 | 64 |
>
65 | 66 |
67 | 70 | 73 |
74 |
75 | 76 |
77 | 78 | 123 | 124 | 125 |
126 | 127 | 128 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /tosec/script/main.js: -------------------------------------------------------------------------------- 1 | var AdfViewer = function(){ 2 | var me = {}; 3 | 4 | var currentSector; 5 | var files; 6 | var fileIndex; 7 | var diskIcon = ' '; 8 | 9 | me.load = function(url){ 10 | if (!url) url = el("diskurl").value; 11 | 12 | if (typeof url == "string"){ 13 | if (url == "") return; 14 | } 15 | 16 | adf.loadDisk(url,function(success){ 17 | if (success){ 18 | var info = adf.getInfo(); 19 | if (info.diskFormat == "DOS"){ 20 | el("feedback").style.display = "none"; 21 | el("folder").style.display = "block"; 22 | el("filemanager").style.display = "block"; 23 | me.showRoot(); 24 | }else{ 25 | el("feedback").innerHTML = 'Sorry, This does not seem to be an AmigaDOS disk
OK
'; 26 | el("feedback").style.display = "block"; 27 | } 28 | }else{ 29 | el("feedback").innerHTML = 'This does not seem to be a standard Amiga DD disk file
OK
'; 30 | el("feedback").style.display = "block"; 31 | } 32 | }); 33 | }; 34 | 35 | function listFolder(folder){ 36 | 37 | var container = el("list"); 38 | container.innerHTML = ""; 39 | 40 | var path = adf.getInfo().label; 41 | if (folder.parent){ 42 | container.appendChild(createListItem({ 43 | sector: folder.parent, 44 | name: "..", 45 | type: "DIR" 46 | })); 47 | path += "/" + folder.name; 48 | } 49 | 50 | el("disklabel").innerHTML = path; 51 | 52 | 53 | function sortByName(a,b) { 54 | if (a.name < b.name) 55 | return -1; 56 | if (a.name > b.name) 57 | return 1; 58 | return 0; 59 | } 60 | folder.folders.sort(sortByName); 61 | folder.files.sort(sortByName); 62 | 63 | 64 | folder.folders.forEach(function(f){ 65 | container.appendChild(createListItem(f)); 66 | }); 67 | 68 | folder.files.forEach(function(f){ 69 | container.appendChild(createListItem(f)); 70 | }); 71 | 72 | showInfo(folder); 73 | } 74 | 75 | function createListItem(f){ 76 | var item = document.createElement("div"); 77 | item.className = "listitem " + f.type; 78 | 79 | var icon = document.createElement("i"); 80 | icon.className = "fa fa-folder"; 81 | 82 | var label = document.createElement("span"); 83 | label.className = "label"; 84 | label.innerHTML = f.name; 85 | 86 | var size; 87 | if (f.type == "FILE"){ 88 | icon.className = "fa fa-file-o"; 89 | 90 | size = document.createElement("span"); 91 | size.className = "size"; 92 | size.innerHTML = formatSize(f.size); 93 | } 94 | 95 | item.onclick = function(){ 96 | if (f.type == "FILE"){ 97 | showInfo(f); 98 | }else{ 99 | var dir = adf.readFolderAtSector(f.sector); 100 | listFolder(dir); 101 | } 102 | 103 | }; 104 | 105 | item.appendChild(icon); 106 | item.appendChild(label); 107 | if (size) item.appendChild(size); 108 | 109 | return item; 110 | } 111 | 112 | function showInfo(f){ 113 | var container = el("fileinfo"); 114 | 115 | var content = ""; 116 | content += '

' + f.name + '

'; 117 | content += ""; 118 | 119 | if (f.size) content += ""; 120 | if (f.comment) content += ""; 121 | if (f.lastChangeDays && f.lastChangeDays>1000){ 122 | content += ""; 123 | } 124 | 125 | content += "
Type:" + f.type + "
Size:" + formatSize(f.size) + "
Comment:" + f.comment + "
LastChanged:" + formatDateTime(f.lastChangeDays,f.lastChangeMinutes,f.lastChangeTicks) + "
"; 126 | 127 | 128 | if (f.type == "FILE"){ 129 | content += "

Actions

"; 130 | content += '
Show as text
'; 131 | content += '
Show as hex
'; 132 | content += '
Download
'; 133 | } 134 | 135 | content += "
"; 136 | container.innerHTML = content; 137 | } 138 | 139 | function el(id){ 140 | return document.getElementById(id); 141 | } 142 | 143 | function formatSize(size){ 144 | var result = Math.round(size / 1024); 145 | if (result == 0) result = 1; 146 | return result + " kb"; 147 | } 148 | 149 | function formatDateTime(days,minutes,ticks){ 150 | var start = 252457200000; // 1 jan 1978; 151 | var monthNames = ["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"]; 152 | 153 | // ticks = 50 ticks a second 154 | var d = new Date(start + (days * 86400000) + (minutes * 3600000) + (ticks * 50000)); 155 | var m = d.getMinutes(); 156 | var h = d.getHours(); 157 | if (m<10) m = "0" + m; 158 | if (h<10) m = "0" + h; 159 | return d.getDate() + " " + monthNames[d.getMonth()] + " " + d.getFullYear() + " " + h + ":" + m; 160 | } 161 | 162 | me.showAscii = function(sector){ 163 | showFile(sector,true); 164 | }; 165 | 166 | me.showHex = function(sector){ 167 | showFile(sector,false); 168 | }; 169 | 170 | function showFile(sector,asAscii){ 171 | currentSector = sector; 172 | var file = adf.readFileAtSector(sector,true); 173 | 174 | el("filelabel").innerHTML = file.name; 175 | 176 | el("file").style.display = "block"; 177 | el("folder").style.display = "none"; 178 | 179 | var hex = el("hex"); 180 | var ascii = el("ascii"); 181 | hex.className = asAscii ? "ascii" : "hex"; 182 | ascii.className = asAscii ? "ascii" : "hex"; 183 | 184 | var s = ""; 185 | var a = ""; 186 | 187 | for (var i = 1; i<= file.size; i++){ 188 | var eol = ""; 189 | if (i%16 == 0) eol = "\n"; 190 | var b = file.content[i-1]; 191 | s += formatHex(b) + " " + eol; 192 | a += String.fromCharCode(b); 193 | if (!asAscii) (a += " " + eol); 194 | } 195 | 196 | hex.value = s; 197 | ascii.value = a; 198 | } 199 | 200 | me.showFolder = function(){ 201 | el("file").style.display = "none"; 202 | el("folder").style.display = "block"; 203 | el("raw").style.display = "none"; 204 | }; 205 | 206 | me.showRoot = function(){ 207 | listFolder(adf.readRootFolder()); 208 | }; 209 | 210 | me.download = function(sector){ 211 | sector = sector || currentSector; 212 | var file = adf.readFileAtSector(sector,true); 213 | 214 | 215 | var b = new Blob([file.content], {type: "application/octet-stream"}); 216 | 217 | var fileName = file.name; 218 | saveAs(b,fileName); 219 | }; 220 | 221 | me.showSector = function(sector){ 222 | currentSector = sector || 0; 223 | 224 | if (isNaN(currentSector)) currentSector = 0; 225 | if (currentSector<0) currentSector=0; 226 | if (currentSector>=1760) currentSector = 1759; 227 | 228 | el("sector").value = currentSector; 229 | el("sectorinfo").innerHTML = adf.getSectorType(sector); 230 | 231 | el("file").style.display = "none"; 232 | el("folder").style.display = "none"; 233 | el("raw").style.display = "block"; 234 | 235 | var content = adf.readSector(currentSector); 236 | 237 | var hex = el("sectorhex"); 238 | var ascii = el("sectorascii"); 239 | 240 | var s = ""; 241 | var a = ""; 242 | 243 | for (var i = 1; i<= content.length; i++){ 244 | var eol = ""; 245 | if (i%16 == 0) eol = "\n"; 246 | var b = content[i-1]; 247 | s += formatHex(b) + " " + eol; 248 | a += String.fromCharCode(b) + " " + eol; 249 | } 250 | 251 | hex.value = s; 252 | ascii.value = a; 253 | 254 | }; 255 | 256 | me.nextSector = function(){ 257 | me.showSector(++currentSector); 258 | }; 259 | me.prevSector = function(){ 260 | me.showSector(--currentSector); 261 | }; 262 | me.onSectorUpdate = function(){ 263 | var value = el("sector").value; 264 | if (isNaN(value)) value = 0; 265 | if (value != currentSector) me.showSector(value); 266 | }; 267 | 268 | me.handleDragEnter = function(e){ 269 | e.stopPropagation(); 270 | e.preventDefault(); 271 | el("dropzone").classList.add("over"); 272 | }; 273 | 274 | me.handleDragLeave = function(e){ 275 | e.stopPropagation(); 276 | e.preventDefault(); 277 | el("dropzone").classList.remove("over"); 278 | }; 279 | 280 | me.handleDragOver = function(e){ 281 | e.stopPropagation(); 282 | e.preventDefault(); 283 | }; 284 | 285 | me.handleDrop = function(e){ 286 | e.stopPropagation(); 287 | e.preventDefault(); 288 | el("dropzone").classList.remove("over"); 289 | el("dropzone").classList.add("small"); 290 | 291 | var dt = e.dataTransfer; 292 | files = dt.files; 293 | var filelist = el("filelist"); 294 | 295 | el("filemanager").style.display = "none"; 296 | el("closebutton").onclick = function(){ 297 | el("filemanager").style.display = "none"; 298 | el("feedback").style.display = "none"; 299 | filelist.style.display = "block"; 300 | }; 301 | el("feedback").onclick = el("closebutton").onclick; 302 | 303 | if (files.length){ 304 | var file; 305 | /*if (files.length == 1){ 306 | filelist.style.display = "none"; 307 | file = files[0]; 308 | el("feedback").innerHTML = "checking " + file.name; 309 | el("feedback").style.display = "block"; 310 | 311 | var reader = new FileReader(); 312 | reader.onload = function(){ 313 | me.load(reader.result); 314 | }; 315 | reader.readAsArrayBuffer(file); 316 | }else{*/ 317 | filelist.innerHTML = '
Name
TOSEC
'; 318 | filelist.style.display = "block"; 319 | 320 | for (var i = 0, max=files.length;io;){if(this.hashed&&(this.hashed=!1,h[0]=h[16],h[16]=h[1]=h[2]=h[3]=h[4]=h[5]=h[6]=h[7]=h[8]=h[9]=h[10]=h[11]=h[12]=h[13]=h[14]=h[15]=0),r)if(ARRAY_BUFFER)for(i=this.start;e>o&&64>i;++o)f[i++]=t[o];else for(i=this.start;e>o&&64>i;++o)h[i>>2]|=t[o]<o&&64>i;++o)s=t.charCodeAt(o),128>s?f[i++]=s:2048>s?(f[i++]=192|s>>6,f[i++]=128|63&s):55296>s||s>=57344?(f[i++]=224|s>>12,f[i++]=128|s>>6&63,f[i++]=128|63&s):(s=65536+((1023&s)<<10|1023&t.charCodeAt(++o)),f[i++]=240|s>>18,f[i++]=128|s>>12&63,f[i++]=128|s>>6&63,f[i++]=128|63&s);else for(i=this.start;e>o&&64>i;++o)s=t.charCodeAt(o),128>s?h[i>>2]|=s<s?(h[i>>2]|=(192|s>>6)<>2]|=(128|63&s)<s||s>=57344?(h[i>>2]|=(224|s>>12)<>2]|=(128|s>>6&63)<>2]|=(128|63&s)<>2]|=(240|s>>18)<>2]|=(128|s>>12&63)<>2]|=(128|s>>6&63)<>2]|=(128|63&s)<=64?(this.start=i-64,this.hash(),this.hashed=!0):this.start=i}return this}},Md5.prototype.finalize=function(){if(!this.finalized){this.finalized=!0;var t=this.blocks,r=this.lastByteIndex;t[r>>2]|=EXTRA[3&r],r>=56&&(this.hashed||this.hash(),t[0]=t[16],t[16]=t[1]=t[2]=t[3]=t[4]=t[5]=t[6]=t[7]=t[8]=t[9]=t[10]=t[11]=t[12]=t[13]=t[14]=t[15]=0),t[14]=this.bytes<<3,this.hash()}},Md5.prototype.hash=function(){var t,r,e,s,i,o,h=this.blocks;this.first?(t=h[0]-680876937,t=(t<<7|t>>>25)-271733879<<0,s=(-1732584194^2004318071&t)+h[1]-117830708,s=(s<<12|s>>>20)+t<<0,e=(-271733879^s&(-271733879^t))+h[2]-1126478375,e=(e<<17|e>>>15)+s<<0,r=(t^e&(s^t))+h[3]-1316259209,r=(r<<22|r>>>10)+e<<0):(t=this.h0,r=this.h1,e=this.h2,s=this.h3,t+=(s^r&(e^s))+h[0]-680876936,t=(t<<7|t>>>25)+r<<0,s+=(e^t&(r^e))+h[1]-389564586,s=(s<<12|s>>>20)+t<<0,e+=(r^s&(t^r))+h[2]+606105819,e=(e<<17|e>>>15)+s<<0,r+=(t^e&(s^t))+h[3]-1044525330,r=(r<<22|r>>>10)+e<<0),t+=(s^r&(e^s))+h[4]-176418897,t=(t<<7|t>>>25)+r<<0,s+=(e^t&(r^e))+h[5]+1200080426,s=(s<<12|s>>>20)+t<<0,e+=(r^s&(t^r))+h[6]-1473231341,e=(e<<17|e>>>15)+s<<0,r+=(t^e&(s^t))+h[7]-45705983,r=(r<<22|r>>>10)+e<<0,t+=(s^r&(e^s))+h[8]+1770035416,t=(t<<7|t>>>25)+r<<0,s+=(e^t&(r^e))+h[9]-1958414417,s=(s<<12|s>>>20)+t<<0,e+=(r^s&(t^r))+h[10]-42063,e=(e<<17|e>>>15)+s<<0,r+=(t^e&(s^t))+h[11]-1990404162,r=(r<<22|r>>>10)+e<<0,t+=(s^r&(e^s))+h[12]+1804603682,t=(t<<7|t>>>25)+r<<0,s+=(e^t&(r^e))+h[13]-40341101,s=(s<<12|s>>>20)+t<<0,e+=(r^s&(t^r))+h[14]-1502002290,e=(e<<17|e>>>15)+s<<0,r+=(t^e&(s^t))+h[15]+1236535329,r=(r<<22|r>>>10)+e<<0,t+=(e^s&(r^e))+h[1]-165796510,t=(t<<5|t>>>27)+r<<0,s+=(r^e&(t^r))+h[6]-1069501632,s=(s<<9|s>>>23)+t<<0,e+=(t^r&(s^t))+h[11]+643717713,e=(e<<14|e>>>18)+s<<0,r+=(s^t&(e^s))+h[0]-373897302,r=(r<<20|r>>>12)+e<<0,t+=(e^s&(r^e))+h[5]-701558691,t=(t<<5|t>>>27)+r<<0,s+=(r^e&(t^r))+h[10]+38016083,s=(s<<9|s>>>23)+t<<0,e+=(t^r&(s^t))+h[15]-660478335,e=(e<<14|e>>>18)+s<<0,r+=(s^t&(e^s))+h[4]-405537848,r=(r<<20|r>>>12)+e<<0,t+=(e^s&(r^e))+h[9]+568446438,t=(t<<5|t>>>27)+r<<0,s+=(r^e&(t^r))+h[14]-1019803690,s=(s<<9|s>>>23)+t<<0,e+=(t^r&(s^t))+h[3]-187363961,e=(e<<14|e>>>18)+s<<0,r+=(s^t&(e^s))+h[8]+1163531501,r=(r<<20|r>>>12)+e<<0,t+=(e^s&(r^e))+h[13]-1444681467,t=(t<<5|t>>>27)+r<<0,s+=(r^e&(t^r))+h[2]-51403784,s=(s<<9|s>>>23)+t<<0,e+=(t^r&(s^t))+h[7]+1735328473,e=(e<<14|e>>>18)+s<<0,r+=(s^t&(e^s))+h[12]-1926607734,r=(r<<20|r>>>12)+e<<0,i=r^e,t+=(i^s)+h[5]-378558,t=(t<<4|t>>>28)+r<<0,s+=(i^t)+h[8]-2022574463,s=(s<<11|s>>>21)+t<<0,o=s^t,e+=(o^r)+h[11]+1839030562,e=(e<<16|e>>>16)+s<<0,r+=(o^e)+h[14]-35309556,r=(r<<23|r>>>9)+e<<0,i=r^e,t+=(i^s)+h[1]-1530992060,t=(t<<4|t>>>28)+r<<0,s+=(i^t)+h[4]+1272893353,s=(s<<11|s>>>21)+t<<0,o=s^t,e+=(o^r)+h[7]-155497632,e=(e<<16|e>>>16)+s<<0,r+=(o^e)+h[10]-1094730640,r=(r<<23|r>>>9)+e<<0,i=r^e,t+=(i^s)+h[13]+681279174,t=(t<<4|t>>>28)+r<<0,s+=(i^t)+h[0]-358537222,s=(s<<11|s>>>21)+t<<0,o=s^t,e+=(o^r)+h[3]-722521979,e=(e<<16|e>>>16)+s<<0,r+=(o^e)+h[6]+76029189,r=(r<<23|r>>>9)+e<<0,i=r^e,t+=(i^s)+h[9]-640364487,t=(t<<4|t>>>28)+r<<0,s+=(i^t)+h[12]-421815835,s=(s<<11|s>>>21)+t<<0,o=s^t,e+=(o^r)+h[15]+530742520,e=(e<<16|e>>>16)+s<<0,r+=(o^e)+h[2]-995338651,r=(r<<23|r>>>9)+e<<0,t+=(e^(r|~s))+h[0]-198630844,t=(t<<6|t>>>26)+r<<0,s+=(r^(t|~e))+h[7]+1126891415,s=(s<<10|s>>>22)+t<<0,e+=(t^(s|~r))+h[14]-1416354905,e=(e<<15|e>>>17)+s<<0,r+=(s^(e|~t))+h[5]-57434055,r=(r<<21|r>>>11)+e<<0,t+=(e^(r|~s))+h[12]+1700485571,t=(t<<6|t>>>26)+r<<0,s+=(r^(t|~e))+h[3]-1894986606,s=(s<<10|s>>>22)+t<<0,e+=(t^(s|~r))+h[10]-1051523,e=(e<<15|e>>>17)+s<<0,r+=(s^(e|~t))+h[1]-2054922799,r=(r<<21|r>>>11)+e<<0,t+=(e^(r|~s))+h[8]+1873313359,t=(t<<6|t>>>26)+r<<0,s+=(r^(t|~e))+h[15]-30611744,s=(s<<10|s>>>22)+t<<0,e+=(t^(s|~r))+h[6]-1560198380,e=(e<<15|e>>>17)+s<<0,r+=(s^(e|~t))+h[13]+1309151649,r=(r<<21|r>>>11)+e<<0,t+=(e^(r|~s))+h[4]-145523070,t=(t<<6|t>>>26)+r<<0,s+=(r^(t|~e))+h[11]-1120210379,s=(s<<10|s>>>22)+t<<0,e+=(t^(s|~r))+h[2]+718787259,e=(e<<15|e>>>17)+s<<0,r+=(s^(e|~t))+h[9]-343485551,r=(r<<21|r>>>11)+e<<0,this.first?(this.h0=t+1732584193<<0,this.h1=r-271733879<<0,this.h2=e-1732584194<<0,this.h3=s+271733878<<0,this.first=!1):(this.h0=this.h0+t<<0,this.h1=this.h1+r<<0,this.h2=this.h2+e<<0,this.h3=this.h3+s<<0)},Md5.prototype.hex=function(){this.finalize();var t=this.h0,r=this.h1,e=this.h2,s=this.h3;return HEX_CHARS[t>>4&15]+HEX_CHARS[15&t]+HEX_CHARS[t>>12&15]+HEX_CHARS[t>>8&15]+HEX_CHARS[t>>20&15]+HEX_CHARS[t>>16&15]+HEX_CHARS[t>>28&15]+HEX_CHARS[t>>24&15]+HEX_CHARS[r>>4&15]+HEX_CHARS[15&r]+HEX_CHARS[r>>12&15]+HEX_CHARS[r>>8&15]+HEX_CHARS[r>>20&15]+HEX_CHARS[r>>16&15]+HEX_CHARS[r>>28&15]+HEX_CHARS[r>>24&15]+HEX_CHARS[e>>4&15]+HEX_CHARS[15&e]+HEX_CHARS[e>>12&15]+HEX_CHARS[e>>8&15]+HEX_CHARS[e>>20&15]+HEX_CHARS[e>>16&15]+HEX_CHARS[e>>28&15]+HEX_CHARS[e>>24&15]+HEX_CHARS[s>>4&15]+HEX_CHARS[15&s]+HEX_CHARS[s>>12&15]+HEX_CHARS[s>>8&15]+HEX_CHARS[s>>20&15]+HEX_CHARS[s>>16&15]+HEX_CHARS[s>>28&15]+HEX_CHARS[s>>24&15]},Md5.prototype.toString=Md5.prototype.hex,Md5.prototype.digest=function(){this.finalize();var t=this.h0,r=this.h1,e=this.h2,s=this.h3;return[255&t,t>>8&255,t>>16&255,t>>24&255,255&r,r>>8&255,r>>16&255,r>>24&255,255&e,e>>8&255,e>>16&255,e>>24&255,255&s,s>>8&255,s>>16&255,s>>24&255]},Md5.prototype.array=Md5.prototype.digest,Md5.prototype.arrayBuffer=function(){this.finalize();var t=new ArrayBuffer(16),r=new Uint32Array(t);return r[0]=this.h0,r[1]=this.h1,r[2]=this.h2,r[3]=this.h3,t},Md5.prototype.buffer=Md5.prototype.arrayBuffer,Md5.prototype.base64=function(){for(var t,r,e,s="",i=this.array(),o=0;15>o;)t=i[o++],r=i[o++],e=i[o++],s+=BASE64_ENCODE_CHAR[t>>>2]+BASE64_ENCODE_CHAR[63&(t<<4|r>>>4)]+BASE64_ENCODE_CHAR[63&(r<<2|e>>>6)]+BASE64_ENCODE_CHAR[63&e];return t=i[o],s+=BASE64_ENCODE_CHAR[t>>>2]+BASE64_ENCODE_CHAR[t<<4&63]+"=="};var exports=createMethod();COMMON_JS?module.exports=exports:(root.md5=exports,AMD&&define(function(){return exports}))}(); -------------------------------------------------------------------------------- /tosec/style/main.css: -------------------------------------------------------------------------------- 1 | html,body{ 2 | margin: 0; 3 | padding: 0; 4 | font-family: Helvetica, Arial, sans-serif; 5 | font-size: 14px; 6 | box-sizing: border-box; 7 | } 8 | 9 | *, *:before, *:after { 10 | box-sizing: inherit; 11 | } 12 | 13 | .clear{ 14 | clear: both; 15 | } 16 | 17 | #container, 18 | #filelist{ 19 | width: 800px; 20 | margin: auto; 21 | max-width: 98%; 22 | } 23 | 24 | textarea{ 25 | font-family: "Courier New",monospace; 26 | font-size: 13px; 27 | } 28 | 29 | #dropzone{ 30 | border: 5px solid silver; 31 | margin: 10px 0; 32 | padding: 10px; 33 | color: grey; 34 | text-align: center; 35 | padding-top: 60%; 36 | background-image: url("../amiga.png"); 37 | background-size: contain; 38 | background-repeat: no-repeat; 39 | background-position: center center; 40 | 41 | border-radius: 10px; 42 | } 43 | 44 | #dropzone.small{ 45 | padding: 80px 10px 1px 10px; 46 | } 47 | 48 | #dropzone.over{ 49 | border: 5px solid #427fb7; 50 | background-color: #ecedfa; 51 | } 52 | 53 | #dropzone .selector{ 54 | float: right; 55 | } 56 | 57 | #filemanager{ 58 | display: none; 59 | } 60 | 61 | #filemanager .panel{ 62 | border: 1px solid silver; 63 | } 64 | 65 | .caption{ 66 | background-color: #427fb7; 67 | color: white; 68 | padding: 4px; 69 | position: relative; 70 | } 71 | 72 | .caption.amiga{ 73 | background-image: url("../../img/amiga.svg"); 74 | background-size: 20px 16px; 75 | background-position: 2px 4px; 76 | background-repeat: no-repeat; 77 | 78 | padding: 4px 4px 4px 24px; 79 | } 80 | 81 | .diskheader{ 82 | position: relative; 83 | border-bottom: 1px solid silver; 84 | min-height: 24px; 85 | } 86 | 87 | .diskheader .button{ 88 | display: inline-block; 89 | position: absolute; 90 | padding: 4px; 91 | background-color: #c0d2dc; 92 | } 93 | 94 | .diskheader .button:hover{ 95 | cursor: pointer; 96 | background-color: #d5e8f2; 97 | } 98 | 99 | .diskheader .itemlabel{ 100 | padding: 4px 4px 4px 44px; 101 | min-height: 24px; 102 | } 103 | 104 | .diskheader .button.right{ 105 | right: 0; 106 | } 107 | 108 | .diskheader .inline, 109 | .diskheader .button.inline{ 110 | display: inline-block; 111 | padding: 2px 4px; 112 | position: relative; 113 | } 114 | 115 | .diskheader input{ 116 | width: 50px; 117 | text-align: center; 118 | border: 0; 119 | display: inline-block; 120 | } 121 | 122 | #list, 123 | #hex, 124 | #sectorhex{ 125 | height: 300px; 126 | width: 500px; 127 | overflow: scroll; 128 | position: absolute; 129 | } 130 | 131 | 132 | #fileinfo, 133 | #ascii, 134 | #sectorascii{ 135 | width: 300px; 136 | height: 300px; 137 | float: right; 138 | background-color: #f8f8f8; 139 | border-left: 1px solid silver; 140 | padding: 4px; 141 | font-size: 12px; 142 | } 143 | 144 | #hex.ascii{ 145 | display: none; 146 | } 147 | #ascii.ascii{ 148 | width: 800px; 149 | } 150 | 151 | #fileinfo h3{ 152 | margin: 0; 153 | padding: 0; 154 | font-size: 14px; 155 | } 156 | 157 | #fileinfo h4{ 158 | margin: 10px 0 4px 0; 159 | padding: 0 0 2px 0; 160 | font-size: 12px; 161 | border-bottom: 1px solid silver; 162 | } 163 | 164 | #fileinfo .info{ 165 | padding: 4px 4px 4px 20px; 166 | } 167 | 168 | #fileinfo td{ 169 | font-size: 12px; 170 | border-bottom: 1px solid silver; 171 | } 172 | 173 | #fileinfo .action{ 174 | padding: 2px 0; 175 | color: #427fb7; 176 | } 177 | 178 | #fileinfo .action:hover{ 179 | cursor: pointer; 180 | color: #079bd7; 181 | text-decoration: underline; 182 | } 183 | 184 | .listitem{ 185 | padding: 4px 8px; 186 | border-bottom: 1px solid silver; 187 | } 188 | 189 | .listitem i{ 190 | display: inline-block; 191 | width: 20px; 192 | color: #427fb7; 193 | } 194 | 195 | .listitem.DIR i{ 196 | color: #dcc200; 197 | } 198 | 199 | .listitem .label{ 200 | display: inline-block; 201 | width: 200px; 202 | } 203 | 204 | .listitem.DIR{ 205 | background-color: #F5f5f5; 206 | } 207 | 208 | .listitem:hover, 209 | #filelist .file:hover, 210 | #filelist .file.unknown:hover{ 211 | cursor: pointer; 212 | border-bottom: 1px solid #485f74; 213 | background-color: #deebf5; 214 | } 215 | 216 | #feedback{ 217 | border: 2px solid #5B6FC0; 218 | margin: 10px 0; 219 | padding: 10px; 220 | text-align: center; 221 | } 222 | 223 | #feedback:hover{ 224 | cursor: pointer; 225 | } 226 | 227 | #feedback:hover .button{ 228 | background-color: #deebf5; 229 | } 230 | 231 | #feedback .button{ 232 | border: 1px solid #5B6FC0; 233 | margin: 5px auto; 234 | padding: 4px 10px; 235 | width: 100px; 236 | background-color: white; 237 | } 238 | 239 | .footer{ 240 | margin: 30px 0 60px 0; 241 | text-align: center; 242 | font-size: 12px; 243 | color: #44403a; 244 | position: relative; 245 | 246 | 247 | background: #f4f3eb; /* Old browsers */ 248 | background: -moz-linear-gradient(top, #f4f3eb 1%, #e5dec9 100%); /* FF3.6-15 */ 249 | background: -webkit-linear-gradient(top, #f4f3eb 1%,#e5dec9 100%); /* Chrome10-25,Safari5.1-6 */ 250 | background: linear-gradient(to bottom, #f4f3eb 1%,#e5dec9 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ 251 | 252 | border-radius: 10px; 253 | 254 | border: 2px solid rgba(0, 0, 0, 0.07); 255 | } 256 | 257 | .footer .top{ 258 | position: absolute; 259 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAWCAMAAADO+P1vAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkI0M0I1RkI5MDU5QzExRTg4MTQ2QzQxRDJFRTM3MjI1IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkI0M0I1RkJBMDU5QzExRTg4MTQ2QzQxRDJFRTM3MjI1Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QjQzQjVGQjcwNTlDMTFFODgxNDZDNDFEMkVFMzcyMjUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QjQzQjVGQjgwNTlDMTFFODgxNDZDNDFEMkVFMzcyMjUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz45bR0eAAAApVBMVEXAt6f49/KooJKnnpCpoZPPxrTPxbPLwbDKwbD7+/mooJHMwrHMwrCon5GpoZLn5d3m5d24sqnPxrO5ubfu7eX4+PPp6ODOxbL5+PTPyL2vrKjm5dzQxrPe18unn5Cnn5G/tqXOxbP49/HQxrTMw7HQx7TTybj+/v2/taXQx7X08urn5t3Mw7KsqaXn5t7z8um/tqasqab08+rz8ur8+/n08+v///9VzInbAAAAjUlEQVR42mzO2Q6CMBCF4akbqCjuu6IiqGDp7vs/mtMW5cZz9eVPJhl4/wZ3QsjCUxtjqv+cT7fHHLRCig48X6BlQ2VUU2Ulxt9aihb3LLDyzFK62r25apkOXY1t9SzpgB8i6LOCTZCzqK4j3gvq6rhBxjQ5X0JYMsX29PRYh3DFf1e7Ng4knhFt9xFgAPAcIX2WAh/+AAAAAElFTkSuQmCC'); 260 | background-size: 10px 30px; 261 | height: 30px; 262 | left: 16px; 263 | right: 16px; 264 | top: -12px; 265 | 266 | } 267 | 268 | .footer .barstop{ 269 | height: 30px; 270 | margin: 28px 20px 20px 20px; 271 | background: linear-gradient(#f4f3eb 42%, transparent 0, transparent 88%, #fffcef 0), rgba(178, 161, 131, 0.71); 272 | background-size: 25px 9px; 273 | } 274 | 275 | .footer .barsbottom{ 276 | height: 30px; 277 | margin: 20px; 278 | background: linear-gradient(#E7E0CD 42%, transparent 0, transparent 88%, #fff8dd 0), rgba(155, 138, 108, 0.71); 279 | background-size: 25px 9px; 280 | } 281 | 282 | 283 | .footer a{ 284 | color: #44403a; 285 | text-decoration: underline; 286 | } 287 | 288 | .footer b{ 289 | color: #283c5a; 290 | } 291 | 292 | .footer span, 293 | .footer span b{ 294 | color: #7b8598; 295 | } 296 | 297 | 298 | .panels{ 299 | text-align: center; 300 | } 301 | 302 | .panels .panel{ 303 | width: 30%; 304 | margin: 4px; 305 | height: 200px; 306 | display: inline-block; 307 | vertical-align: top; 308 | border: 1px solid rgba(255, 255, 255, 0.25); 309 | box-shadow: inset -1px -1px 1px rgba(255, 255, 255, .8), inset 1px 1px 1px rgba(0, 0, 0, .3); 310 | border-radius: 5px; 311 | padding: 16px; 312 | } 313 | 314 | .panels .panel h2{ 315 | margin: 0 0 10px 0; 316 | padding: 4px; 317 | font-size: 13px; 318 | border-bottom: 1px solid rgba(0,0,0, .3); 319 | box-shadow: 0 1px 1px rgba(255, 255, 255, .8); 320 | } 321 | 322 | .footer .panelwide{ 323 | margin: 4px 3.5%; 324 | border: 1px solid rgba(255, 255, 255, 0.25); 325 | box-shadow: inset -1px -1px 1px rgba(255, 255, 255, .8), inset 1px 1px 1px rgba(0, 0, 0, .3); 326 | border-radius: 5px; 327 | padding: 16px; 328 | } 329 | 330 | #feedback, 331 | #folder, 332 | #file, 333 | #raw{ 334 | display: none; 335 | } 336 | 337 | 338 | 339 | #filelist .file{ 340 | border-bottom: 1px solid #c5d0d1; 341 | padding: 2px; 342 | position: relative; 343 | } 344 | 345 | #filelist .file.unknown{ 346 | color: #357762; 347 | background-color: #e0fabc; 348 | border-bottom: 1px solid #7ed16e; 349 | } 350 | #filelist .file.known{ 351 | color: #5f6d80; 352 | border-bottom: 1px solid #c5d0d1; 353 | } 354 | 355 | #filelist .file div, 356 | #filelist .caption div{ 357 | display: inline-block; 358 | } 359 | 360 | #filelist .name{ 361 | width: 40%; 362 | padding-left: 8px; 363 | } 364 | 365 | #filelist .info{ 366 | width: 59%; 367 | } 368 | 369 | #filelist .file div.inspect{ 370 | width: 60px; 371 | position: absolute; 372 | border: 1px solid silver; 373 | background-color: white; 374 | padding: 2px 2px; 375 | font-size: 10px; 376 | text-align: center; 377 | margin-left: -64px; 378 | bottom: 2px; 379 | display: none; 380 | } 381 | 382 | #filelist .file:hover div.inspect{ 383 | display: inline-block; 384 | } 385 | 386 | 387 | #closebutton{ 388 | position: absolute; 389 | right: 0; 390 | top: 0; 391 | color: white; 392 | font-size: 16px; 393 | padding: 4px 10px; 394 | } 395 | 396 | #closebutton:hover{ 397 | cursor: pointer; 398 | font-weight: bold; 399 | } 400 | 401 | 402 | @media screen and (max-width: 600px) { 403 | .panels .panel{ 404 | height: 250px; 405 | } 406 | } 407 | 408 | @media screen and (max-width: 500px) { 409 | .panels .panel{ 410 | height: auto; 411 | width: 93%; 412 | } 413 | } --------------------------------------------------------------------------------