Changeset 47:e0839643ff52
- Timestamp:
- 05/23/08 08:13:08
(8 months ago)
- Author:
- Diggory Hardy <diggory.hardy@gmail.com>
- branch:
- default
- convert_revision:
- 19a507e950084f06719d08f2d2fb57d235bb39f1
- Message:
New mtcp utility and changes to paths.
Changed some of mde.resource.paths and mde.mergetag.Reader's handling of resolving mergetag files, and allowed getting a list of files.
Created a simple mergetag-file copy utility.
Fixed mergetag's MTTReader getting array out of bounds exceptions (now throws a mergetag exception).
committer: Diggory Hardy <diggory.hardy@gmail.com>
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r46 |
r47 |
|
| 7 | 7 | Reading ft tutorial |
|---|
| 8 | 8 | Use cartesian coordinates? Or not? |
|---|
| 9 | | Make layout's adjustCellSizes method call setSize? |
|---|
| 10 | | More resizing stuff... |
|---|
| 11 | 9 | |
|---|
| 12 | 10 | |
|---|
| r46 |
r47 |
|
| 1 | 1 | {MT01} |
|---|
| 2 | | <char[]|Renderer="Simple"> |
|---|
| | 2 | !<char[]|Renderer="Simple"> |
|---|
| 3 | 3 | {W1} |
|---|
| 4 | 4 | <int|x=30> |
|---|
| … | … | |
| 12 | 12 | <int|x=20> |
|---|
| 13 | 13 | <int|y=100> |
|---|
| 14 | | <int[][int]|widgetData=[1:[0x4010,50,50],2:[0xB004,3,1,3,1,3],3:[0x3001],0:[0xB004,3,1,2,1,2]]> |
|---|
| | 14 | <int[][int]|widgetData=[1:[0x4010,50,50],2:[0xB004,3,1,1,3,1],3:[0x3001],0:[0xB004,7,1,3,2,3,1,3,2,3]]> |
|---|
| r26 |
r47 |
|
| 2 | 2 | # License: GNU General Public License version 2 or later (see COPYING) |
|---|
| 3 | 3 | |
|---|
| 4 | | version (Posix) { |
|---|
| 5 | | defaulttargets = mde/mde.d |
|---|
| 6 | | } else version (Win32) { |
|---|
| 7 | | defaulttargets = mde\mde.d |
|---|
| 8 | | } |
|---|
| | 4 | defaulttargets = mde/mde.d |
|---|
| 9 | 5 | |
|---|
| 10 | 6 | [*] |
|---|
| … | … | |
| 16 | 12 | target=bin/mde |
|---|
| 17 | 13 | |
|---|
| 18 | | #[mde\mde.d] |
|---|
| 19 | | #target=bin\mde |
|---|
| | 14 | [util/mtcp.d] |
|---|
| | 15 | target=bin/mtcp |
|---|
| 20 | 16 | |
|---|
| 21 | 17 | [test/mdeTest.d] |
|---|
| r45 |
r47 |
|
| 64 | 64 | |
|---|
| 65 | 65 | IReader reader; |
|---|
| 66 | | reader = confDir.makeMTReader (fileName, PRIORITY.HIGH_LOW, null, true); |
|---|
| 67 | | reader.dataSecCreator = delegate mt.IDataSection(mt.ID id) { |
|---|
| 68 | | return new Window (id); |
|---|
| 69 | | }; |
|---|
| 70 | | reader.read; |
|---|
| | 66 | try { |
|---|
| | 67 | reader = confDir.makeMTReader (fileName, PRIORITY.HIGH_LOW, null, true); |
|---|
| | 68 | reader.dataSecCreator = delegate mt.IDataSection(mt.ID id) { |
|---|
| | 69 | return new Window (id); |
|---|
| | 70 | }; |
|---|
| | 71 | reader.read; |
|---|
| | 72 | } catch (Exception e) { |
|---|
| | 73 | logger.error ("Unable to load GUI: errors parsing config file ("~confDir.getFileName(fileName,PRIORITY.HIGH_LOW)~"):"); |
|---|
| | 74 | logger.error (e.msg); |
|---|
| | 75 | throw new GuiException ("Failure parsing config file"); |
|---|
| | 76 | } |
|---|
| 71 | 77 | |
|---|
| 72 | 78 | // Get the renderer |
|---|
| r26 |
r47 |
|
| 17 | 17 | * This module contains all reading functions, for both binary and text MergeTag files. |
|---|
| 18 | 18 | *************************************************************************************************/ |
|---|
| 19 | | |
|---|
| 20 | 19 | module mde.mergetag.Reader; |
|---|
| 21 | 20 | |
|---|
| … | … | |
| 46 | 45 | /** Make an IReader class. |
|---|
| 47 | 46 | * |
|---|
| 48 | | * If no extension is given, search for a file using each extension (.mtt and .mtb) appended to |
|---|
| 49 | | * path, and set path to the most recent file name. If neither suffix added resolves a valid file, |
|---|
| 50 | | * throw an MTFileIOException with a suitible error message. |
|---|
| 51 | | * |
|---|
| 52 | | * When an extension is available (either after the above or when supplied), use the appropriate |
|---|
| 53 | | * reader (MTT or MTB). |
|---|
| | 47 | * Create an appropriate reader: MTTReader or MTBReader. |
|---|
| 54 | 48 | * |
|---|
| 55 | 49 | * Throws: |
|---|
| 56 | 50 | * $(TABLE |
|---|
| 57 | 51 | * $(TR $(TH Exception) $(TH Thrown when)) |
|---|
| 58 | | * $(TR $(TD MTFileFormatException) $(TD Unable to determine format (only analysing file name))) |
|---|
| 59 | | * $(TR $(TD MTFileIOException) $(TD When no extension is given, neither appending .mtt nor |
|---|
| 60 | | * appending .mtb resolves a valid file)) |
|---|
| | 52 | * $(TR $(TD MTFileIOException) $(TD When extension given is neither mtt nor mtb)) |
|---|
| 61 | 53 | * ) |
|---|
| 62 | 54 | * |
|---|
| 63 | 55 | */ |
|---|
| 64 | | IReader makeReader (char[] path, DataSet ds = null, bool rdHeader = false) { |
|---|
| 65 | | return makeReader (new FilePath(path), ds, rdHeader); |
|---|
| 66 | | } |
|---|
| 67 | 56 | IReader makeReader (PathView path, DataSet ds = null, bool rdHeader = false) { |
|---|
| 68 | | if (path.ext.length == 0) { |
|---|
| 69 | | PathView tPath = new FilePath (path.toString ~ ".mtt"); |
|---|
| 70 | | PathView bPath = new FilePath (path.toString ~ ".mtb"); |
|---|
| 71 | | |
|---|
| 72 | | bool bPathExists = bPath.exists; |
|---|
| 73 | | |
|---|
| 74 | | if (tPath.exists) { |
|---|
| 75 | | if (bPathExists) { |
|---|
| 76 | | // take the latest version (roughly speaking...) |
|---|
| 77 | | path = tPath.modified > bPath.modified ? tPath : bPath; |
|---|
| 78 | | } else path = tPath; |
|---|
| 79 | | } else { |
|---|
| 80 | | if (bPathExists) path = bPath; |
|---|
| 81 | | else { |
|---|
| 82 | | throw new MTFileIOException ("No file exists: "~path.toString~"[.mtt|.mtb]"); |
|---|
| 83 | | } |
|---|
| 84 | | } |
|---|
| 85 | | } |
|---|
| 86 | | |
|---|
| 87 | 57 | if (path.ext == "mtb") return new MTBReader (path, ds, rdHeader); |
|---|
| 88 | 58 | else if (path.ext == "mtt") return new MTTReader (path, ds, rdHeader); |
|---|
| 89 | | else throw new MTFileFormatException; |
|---|
| | 59 | else throw new MTFileIOException ("Invalid mergetag extension"); |
|---|
| | 60 | } |
|---|
| | 61 | |
|---|
| | 62 | /** Resolve a file path. |
|---|
| | 63 | * |
|---|
| | 64 | * Tries adding both ".mtt" and ".mtb" extensions, returning whichever exists (the most recently |
|---|
| | 65 | * modified if both exist), or returns null if neither exist. */ |
|---|
| | 66 | PathView findFile (char[] path) { |
|---|
| | 67 | if (path is null) return null; |
|---|
| | 68 | |
|---|
| | 69 | FilePath tPath = new FilePath (path ~ ".mtt"); |
|---|
| | 70 | FilePath bPath = new FilePath (path ~ ".mtb"); |
|---|
| | 71 | |
|---|
| | 72 | bool bPathExists = bPath.exists; |
|---|
| | 73 | |
|---|
| | 74 | if (tPath.exists) { |
|---|
| | 75 | if (bPathExists) { |
|---|
| | 76 | // take the latest version (roughly speaking...) |
|---|
| | 77 | return (tPath.modified > bPath.modified ? tPath : bPath); |
|---|
| | 78 | } else return tPath; |
|---|
| | 79 | } else { |
|---|
| | 80 | if (bPathExists) return bPath; |
|---|
| | 81 | else return null; |
|---|
| | 82 | } |
|---|
| 90 | 83 | } |
|---|
| 91 | 84 | |
|---|
| … | … | |
| 167 | 160 | IDataSection delegate (ID) _dataSecCreator = null; // see property setter above |
|---|
| 168 | 161 | |
|---|
| 169 | | uint endOfHeader; |
|---|
| | 162 | size_t endOfHeader; |
|---|
| 170 | 163 | bool allRead = false; // true if endOfHeader == fbuf.length or read([]) has run |
|---|
| 171 | 164 | bool fatal = false; // a fatal file error occured; don't try to recover |
|---|
| … | … | |
| 175 | 168 | */ |
|---|
| 176 | 169 | struct SecMD { // sec meta data |
|---|
| 177 | | static SecMD opCall (uint _pos, bool _read) { |
|---|
| | 170 | static SecMD opCall (size_t _pos, bool _read) { |
|---|
| 178 | 171 | SecMD ret; |
|---|
| 179 | 172 | ret.pos = _pos; |
|---|
| … | … | |
| 181 | 174 | return ret; |
|---|
| 182 | 175 | } |
|---|
| 183 | | uint pos; // position to start reading |
|---|
| | 176 | size_t pos; // position to start reading |
|---|
| 184 | 177 | bool read; // true if already read |
|---|
| 185 | 178 | } |
|---|
| … | … | |
| 302 | 295 | } |
|---|
| 303 | 296 | } else { // this time we don't need to use secTable |
|---|
| 304 | | for (uint pos = endOfHeader; pos < fbuf.length;) { |
|---|
| | 297 | for (size_t pos = endOfHeader; pos < fbuf.length;) { |
|---|
| 305 | 298 | ID id = fbufReadSecMarker (pos); |
|---|
| 306 | 299 | IDataSection ds = getOrCreateSec (id); |
|---|
| … | … | |
| 331 | 324 | } |
|---|
| 332 | 325 | } else { |
|---|
| 333 | | for (uint pos = endOfHeader; pos < fbuf.length;) { |
|---|
| | 326 | for (size_t pos = endOfHeader; pos < fbuf.length;) { |
|---|
| 334 | 327 | ID id = fbufReadSecMarker (pos); |
|---|
| 335 | 328 | secTable[id] = SecMD(pos,false); // add to table |
|---|
| … | … | |
| 372 | 365 | slightly faster, but a tiny difference isn't worth the extra effort/risk of using char*'s. |
|---|
| 373 | 366 | */ |
|---|
| 374 | | private uint parseSection (uint pos, IDataSection dsec) { |
|---|
| | 367 | private size_t parseSection (size_t pos, IDataSection dsec) { |
|---|
| | 368 | debug scope (failure) |
|---|
| | 369 | logger.trace ("MTTReader.parseSection: failure"); |
|---|
| 375 | 370 | /* Searches fbuf starting from start to find one of <=>| and stops at its index. |
|---|
| 376 | 371 | |
|---|
| … | … | |
| 379 | 374 | non-ascii UTF-8 char which would look like several chars. |
|---|
| 380 | 375 | */ |
|---|
| 381 | | void fbufLocateDataTagChar (ref uint pos, bool quotable) { |
|---|
| 382 | | for (; pos < fbuf.length; ++pos) { |
|---|
| | 376 | void fbufLocateDataTagChar (ref size_t pos, bool quotable) { |
|---|
| | 377 | while (true) { |
|---|
| | 378 | fbufIncrement (pos); |
|---|
| | 379 | |
|---|
| 383 | 380 | if ((fbuf[pos] >= '<' && fbuf[pos] <= '>') || fbuf[pos] == '|') return; |
|---|
| 384 | 381 | else if (quotable) { |
|---|
| 385 | 382 | char c = fbuf[pos]; |
|---|
| 386 | 383 | if (c == '\'' || c == '"') { |
|---|
| 387 | | ++pos; |
|---|
| | 384 | fbufIncrement(pos); |
|---|
| 388 | 385 | while (fbuf[pos] != c) { |
|---|
| 389 | 386 | if (fbuf[pos] == '\\') ++pos; // escape seq. |
|---|
| 390 | 387 | fbufIncrement(pos); |
|---|
| 391 | | } |
|---|
| | 388 | } |
|---|
| 392 | 389 | } |
|---|
| 393 | 390 | } |
|---|
| … | … | |
| 402 | 399 | char[] ErrDTAG = "Bad data tag format: not <type|id=data>" ~ ErrInFile; |
|---|
| 403 | 400 | |
|---|
| 404 | | fbufIncrement (pos); |
|---|
| 405 | | |
|---|
| 406 | 401 | // Type section of tag: |
|---|
| 407 | | uint pos_s = pos; |
|---|
| | 402 | size_t pos_s = pos + 1; |
|---|
| 408 | 403 | fbufLocateDataTagChar (pos, false); // find end of type section |
|---|
| 409 | 404 | if (fbuf[pos] != '|') throwMTErr (ErrDTAG, new MTSyntaxException); |
|---|
| 410 | 405 | char[] type = fbuf[pos_s..pos]; |
|---|
| 411 | 406 | |
|---|
| 412 | | fbufIncrement (pos); |
|---|
| 413 | | |
|---|
| 414 | 407 | // ID section of tag: |
|---|
| 415 | | pos_s = pos; |
|---|
| | 408 | pos_s = pos + 1; |
|---|
| 416 | 409 | fbufLocateDataTagChar (pos, false); // find end of type section |
|---|
| 417 | 410 | if (fbuf[pos] != '=') throwMTErr (ErrDTAG, new MTSyntaxException); |
|---|
| 418 | 411 | ID tagID = cast(ID) fbuf[pos_s..pos]; |
|---|
| 419 | 412 | |
|---|
| 420 | | fbufIncrement (pos); |
|---|
| 421 | | |
|---|
| 422 | 413 | // Data section of tag: |
|---|
| 423 | | pos_s = pos; |
|---|
| | 414 | pos_s = pos + 1; |
|---|
| 424 | 415 | fbufLocateDataTagChar (pos, true); // find end of data section |
|---|
| 425 | 416 | if (fbuf[pos] != '>') throwMTErr (ErrDTAG, new MTSyntaxException); |
|---|
| … | … | |
| 434 | 425 | logger.error ("TextException while reading " ~ ErrFile ~ ":"); // following a parse error |
|---|
| 435 | 426 | logger.error (e.msg); |
|---|
| | 427 | // No throw: tag is just ignored |
|---|
| 436 | 428 | } |
|---|
| 437 | 429 | catch (Exception e) { |
|---|
| … | … | |
| 471 | 463 | /* Parses fbuf for a section marker. Already knows fbuf[pos] == '{'. |
|---|
| 472 | 464 | */ |
|---|
| 473 | | private ID fbufReadSecMarker (ref uint pos) { |
|---|
| | 465 | private ID fbufReadSecMarker (ref size_t pos) { |
|---|
| 474 | 466 | // at this point pos is whatever a parseSection run returned |
|---|
| 475 | 467 | // since we haven't hit EOF, fbuf[pos] MUST be '{' so no need to check |
|---|
| 476 | 468 | fbufIncrement(pos); |
|---|
| 477 | 469 | |
|---|
| 478 | | uint start = pos; |
|---|
| | 470 | size_t start = pos; |
|---|
| 479 | 471 | for (; pos < fbuf.length; ++pos) |
|---|
| 480 | 472 | if (fbuf[pos] == '}' || fbuf[pos] == '{') break; |
|---|
| … | … | |
| 489 | 481 | |
|---|
| 490 | 482 | /* Increments pos and checks it hasn't hit fbuf.length . */ |
|---|
| 491 | | private void fbufIncrement(ref uint pos) { |
|---|
| | 483 | private void fbufIncrement(ref size_t pos) { |
|---|
| 492 | 484 | ++pos; |
|---|
| 493 | 485 | if (pos >= fbuf.length) throwMTErr("Unexpected EOF" ~ ErrInFile, new MTSyntaxException); |
|---|
| r44 |
r47 |
|
| 73 | 73 | IReader makeMTReader (char[] file, PRIORITY readOrder, DataSet ds = null, bool rdHeader = false) |
|---|
| 74 | 74 | { |
|---|
| 75 | | if (readOrder == PRIORITY.HIGH_ONLY) { |
|---|
| 76 | | foreach_reverse (path; paths) { // starting with highest-priority path... |
|---|
| 77 | | try { |
|---|
| 78 | | return makeReader (path~file, ds, rdHeader); |
|---|
| 79 | | } |
|---|
| 80 | | catch (MTFileIOException) {} // Ignore errors regarding no file for now. |
|---|
| 81 | | } |
|---|
| | 75 | PathView[] files = getFiles (file, readOrder); |
|---|
| | 76 | if (files is null) |
|---|
| 82 | 77 | throw new MTFileIOException ("Unable to find the file: "~file~"[.mtt|mtb]"); |
|---|
| 83 | | } |
|---|
| 84 | | else return new mdeReader (file, readOrder, ds, rdHeader, paths); |
|---|
| | 78 | |
|---|
| | 79 | return new mdeReader (files, ds, rdHeader); |
|---|
| 85 | 80 | } |
|---|
| 86 | 81 | |
|---|
| … | … | |
| 98 | 93 | } |
|---|
| 99 | 94 | |
|---|
| | 95 | /** Returns a string listing the file name or names (if readOrder is not HIGH_ONLY and multiple |
|---|
| | 96 | * matches are found), or "no file found". Intended for user output only. */ |
|---|
| | 97 | char[] getFileName (char[] file, PRIORITY readOrder) |
|---|
| | 98 | { |
|---|
| | 99 | PathView[] files = getFiles (file, readOrder); |
|---|
| | 100 | if (files is null) |
|---|
| | 101 | return "no file found"; |
|---|
| | 102 | |
|---|
| | 103 | char[] ret = files[0].toString; |
|---|
| | 104 | foreach (f; files[1..$]) |
|---|
| | 105 | ret ~= ", " ~ f.toString; |
|---|
| | 106 | return ret; |
|---|
| | 107 | } |
|---|
| | 108 | |
|---|
| 100 | 109 | /** Check whether the given file exists under any path with either .mtt or .mtb suffix. */ |
|---|
| 101 | 110 | bool exists (char[] file) { |
|---|
| … | … | |
| 108 | 117 | |
|---|
| 109 | 118 | private: |
|---|
| | 119 | PathView[] getFiles (char[] filename, PRIORITY readOrder) |
|---|
| | 120 | in { |
|---|
| | 121 | assert (readOrder == PRIORITY.LOW_HIGH || |
|---|
| | 122 | readOrder == PRIORITY.HIGH_LOW || |
|---|
| | 123 | readOrder == PRIORITY.HIGH_ONLY ); |
|---|
| | 124 | } body { |
|---|
| | 125 | PathView[] ret; |
|---|
| | 126 | if (readOrder == PRIORITY.LOW_HIGH) { |
|---|
| | 127 | for (size_t i = 0; i < pathsLen; ++i) { |
|---|
| | 128 | PathView file = findFile (paths[i]~filename); |
|---|
| | 129 | if (file !is null) |
|---|
| | 130 | ret ~= file; |
|---|
| | 131 | } |
|---|
| | 132 | } else { |
|---|
| | 133 | for (int i = pathsLen - 1; i >= 0; --i) { |
|---|
| | 134 | PathView file = findFile (paths[i]~filename); |
|---|
| | 135 | if (file !is null) { |
|---|
| | 136 | ret ~= file; |
|---|
| | 137 | if (readOrder == PRIORITY.HIGH_ONLY) break; |
|---|
| | 138 | } |
|---|
| | 139 | } |
|---|
| | 140 | } |
|---|
| | 141 | return ret; |
|---|
| | 142 | } |
|---|
| 110 | 143 | |
|---|
| 111 | 144 | // Unconditionally add a path |
|---|
| … | … | |
| 239 | 272 | class mdeReader : IReader |
|---|
| 240 | 273 | { |
|---|
| 241 | | private this (char[] file, PRIORITY readOrder, DataSet ds, bool rdHeader, char[][MAX_PATHS] paths) |
|---|
| 242 | | in { assert (readOrder == PRIORITY.LOW_HIGH || readOrder == PRIORITY.HIGH_LOW); } |
|---|
| 243 | | body { |
|---|
| 244 | | rdOrder = readOrder; |
|---|
| | 274 | private this (PathView[] files, DataSet ds, bool rdHeader) |
|---|
| | 275 | in { |
|---|
| | 276 | assert (files !is null, "mdeReader.this: files is null"); |
|---|
| | 277 | } body { |
|---|
| 245 | 278 | if (ds is null) ds = new DataSet; |
|---|
| 246 | 279 | |
|---|
| 247 | | foreach (path; paths) { |
|---|
| 248 | | try { |
|---|
| 249 | | IReader r = makeReader (path~file, ds, rdHeader); |
|---|
| 250 | | |
|---|
| 251 | | readers[readersLen++] = r; |
|---|
| 252 | | } |
|---|
| 253 | | catch (MTFileIOException) {} // Ignore errors regarding no file for now. |
|---|
| 254 | | } |
|---|
| 255 | | |
|---|
| 256 | | if (readersLen == 0) { // totally failed to find any valid files |
|---|
| 257 | | throw new MTFileIOException ("Unable to find the file: "~file~"[.mtt|mtb]"); |
|---|
| 258 | | } |
|---|
| 259 | | |
|---|
| 260 | | // This is simply the easiest way of adjusting the reading order: |
|---|
| 261 | | if (readOrder == PRIORITY.HIGH_LOW) readers[0..readersLen].reverse; |
|---|
| | 280 | foreach (file; files) { |
|---|
| | 281 | IReader r = makeReader (file, ds, rdHeader); |
|---|
| | 282 | |
|---|
| | 283 | readers[readersLen++] = r; |
|---|
| | 284 | } |
|---|
| 262 | 285 | } |
|---|
| 263 | 286 | |
|---|