Ticket #9085: sci-stringfrag.patch

File sci-stringfrag.patch, 24.9 KB (added by bluegr, 15 years ago)

String fragment removal/replacement

  • console.cpp

     
    13551355                                DebugPrintf("M  dynmem: %d bytes", (*(DynMem *)mobj)._size);
    13561356                                break;
    13571357
    1358                         case MEM_OBJ_STRING_FRAG:
    1359                                 DebugPrintf("F  string fragments");
    1360                                 break;
    1361 
    13621358                        default:
    13631359                                DebugPrintf("I  Invalid (type = %x)", mobj->getType());
    13641360                                break;
     
    14941490        }
    14951491        break;
    14961492
    1497         case MEM_OBJ_STRING_FRAG: {
    1498                 DebugPrintf("string frags\n");
    1499                 break;
    1500         }
    1501 
    15021493        default :
    15031494                DebugPrintf("Invalid type %d\n", mobj->getType());
    15041495                break;
  • engine/game.cpp

     
    330330
    331331        s->script_000 = s->segMan->getScript(script_000_segment);
    332332
    333         s->sys_strings = s->segMan->allocateSysStrings(&s->sys_strings_segment);
    334         s->string_frag_segment = s->segMan->allocateStringFrags();
     333        s->systemStrings = s->segMan->allocateSysStrings(&s->sys_strings_segment);
     334        s->systemStrings->strings[SYS_STRING_SAVEDIR] = (char *)calloc(MAX_SAVE_DIR_SIZE, sizeof(char));
     335        s->systemStrings->strings[SYS_STRING_PARSER_BASE] = (char *)calloc(MAX_PARSER_BASE + 1, sizeof(char));
    335336
    336         // Allocate static buffer for savegame and CWD directories
    337         SystemString *str = &s->sys_strings->strings[SYS_STRING_SAVEDIR];
    338         str->name = strdup("savedir");
    339         str->max_size = MAX_SAVE_DIR_SIZE;
    340         str->value = (reg_t *)calloc(MAX_SAVE_DIR_SIZE, sizeof(reg_t)); // FIXME -- sizeof(char) or sizeof(reg_t) ??
    341         str->value[0].segment = s->string_frag_segment; // Set to empty string
    342         str->value[0].offset = 0;
    343 
    344 
    345337        s->r_acc = s->r_prev = NULL_REG;
    346338        s->restAdjust = 0;
    347339
     
    365357        return 0;
    366358}
    367359
    368 void script_set_gamestate_save_dir(EngineState *s, const char *path) {
    369         SystemString *str = &s->sys_strings->strings[SYS_STRING_SAVEDIR];
    370 
    371         strncpy((char *)str->value, path, str->max_size);               // FIXME -- strncpy or internal_stringfrag_strncpy ?
    372         str->value[str->max_size - 1].segment = s->string_frag_segment; // Make sure to terminate
    373         str->value[str->max_size - 1].offset &= 0xff00; // Make sure to terminate
    374 }
    375 
    376 void internal_stringfrag_strncpy(EngineState *s, reg_t *dest, reg_t *src, int len);
    377 
    378360void script_free_vm_memory(EngineState *s) {
    379361        debug(2, "Freeing VM memory");
    380362
     
    438420        s->status_bar_foreground = 0;
    439421        s->status_bar_background = !s->resMan->isVGA() ? 15 : 255;
    440422
    441         SystemString *str = &s->sys_strings->strings[SYS_STRING_PARSER_BASE];
    442         str->name = strdup("parser-base");
    443         str->max_size = MAX_PARSER_BASE;
    444         str->value = (reg_t *)calloc(MAX_PARSER_BASE + 1, sizeof(char));        // FIXME -- sizeof(char) or sizeof(reg_t) ??
    445         str->value[0].segment = s->string_frag_segment; // Set to empty string
    446         str->value[0].offset = 0; // Set to empty string
    447 
    448423        s->parser_base = make_reg(s->sys_strings_segment, SYS_STRING_PARSER_BASE);
    449424
    450425        s->game_start_time = g_system->getMillis();
  • engine/memobj.cpp

     
    5555        case MEM_OBJ_HUNK:
    5656                mem = new HunkTable();
    5757                break;
    58         case MEM_OBJ_STRING_FRAG:
    59                 mem = new StringFrag();
    60                 break;
    6158        case MEM_OBJ_LISTS:
    6259                mem = new ListTable();
    6360                break;
     
    236233}
    237234
    238235bool SystemStrings::isValidOffset(uint16 offset) const {
    239         return offset < SYS_STRINGS_MAX && strings[offset].name;
     236        return offset < SYS_STRINGS_MAX;
    240237}
    241238
    242239byte *SystemStrings::dereference(reg_t pointer, int *size) {
    243         if (size)
    244                 *size = strings[pointer.offset].max_size;
    245         if (pointer.offset < SYS_STRINGS_MAX && strings[pointer.offset].name)
    246                 return (byte *)(strings[pointer.offset].value);
     240        if (pointer.offset < SYS_STRINGS_MAX) {
     241                if (size)
     242                        *size = strings[pointer.offset].size();
     243                        return (byte *)(strings[pointer.offset].c_str());
     244        }
    247245
    248246        // This occurs in KQ5CD when interacting with certain objects
    249247        warning("Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(pointer));
  • engine/memobj.h

     
    4545        MEM_OBJ_NODES = 7,
    4646        MEM_OBJ_HUNK = 8,
    4747        MEM_OBJ_DYNMEM = 9,
    48         MEM_OBJ_STRING_FRAG = 10,
    4948
    5049        MEM_OBJ_MAX // For sanity checking
    5150};
     
    111110};
    112111
    113112
    114 // TODO: Implement the following class
    115 struct StringFrag : public MemObject {
    116         virtual bool isValidOffset(uint16 offset) const { return false; }
    117 
    118         virtual void saveLoadWithSerializer(Common::Serializer &ser);
    119 };
    120 
    121113struct IntMapper;
    122114
    123115enum {
     
    129121        MAX_PARSER_BASE = 64
    130122};
    131123
    132 struct SystemString {
    133         char *name;
    134         int max_size;
    135         reg_t *value;
    136 };
    137 
    138124struct SystemStrings : public MemObject {
    139         SystemString strings[SYS_STRINGS_MAX];
     125        Common::String strings[SYS_STRINGS_MAX];
    140126
    141127public:
    142         SystemStrings() {
    143                 memset(strings, 0, sizeof(strings));
    144         }
     128        SystemStrings() { }
    145129        ~SystemStrings() {
    146                 for (int i = 0; i < SYS_STRINGS_MAX; i++) {
    147                         SystemString *str = &strings[i];
    148                         if (str->name) {
    149                                 free(str->name);
    150                                 str->name = NULL;
    151 
    152                                 free(str->value);
    153                                 str->value = NULL;
    154 
    155                                 str->max_size = 0;
    156                         }
    157                 }
     130                for (int i = 0; i < SYS_STRINGS_MAX; i++)
     131                        strings[i].clear();
    158132        }
    159133
    160134        virtual bool isValidOffset(uint16 offset) const;
  • engine/savegame.cpp

     
    404404        s.syncAsSint32LE(_markedAsDeleted);
    405405}
    406406
    407 static void sync_SystemString(Common::Serializer &s, SystemString &obj) {
    408         syncCStr(s, &obj.name);
    409         s.syncAsSint32LE(obj.max_size);
    410 
    411         // FIXME: This is a *WEIRD* hack: We sync a reg_t* as if it was a string.
    412         // No idea why, but this mimicks what the old save/load code used to do.
    413         syncCStr(s, (char **)&obj.value);
    414 }
    415 
    416407void SystemStrings::saveLoadWithSerializer(Common::Serializer &s) {
    417         for (int i = 0; i < SYS_STRINGS_MAX; ++i)
    418                 sync_SystemString(s, strings[i]);
     408        if (s.isLoading() && s.getVersion() <= 10) {
     409                Common::String tmp;
     410                // Obsolete: we used to save system strings here
     411                // Savedir
     412                s.syncString(tmp);      // "savedir"
     413                s.skip(4);                      // max size
     414                s.syncString(tmp);      // the actual save dir
     415                // Parser base
     416                s.syncString(tmp);      // "parser-base"
     417                s.skip(4);                      // max size
     418                s.syncString(tmp);      // the actual parser base
     419        }
    419420}
    420421
    421422void DynMem::saveLoadWithSerializer(Common::Serializer &s) {
     
    436437        }
    437438}
    438439
    439 void StringFrag::saveLoadWithSerializer(Common::Serializer &s) {
    440         // TODO
    441 }
    442 
    443440#pragma mark -
    444441
    445442static void sync_songlib_t(Common::Serializer &s, SongLibrary &obj) {
     
    672669        }
    673670}
    674671
    675 void internal_stringfrag_strncpy(EngineState *s, reg_t *dest, reg_t *src, int len);
    676 
    677672EngineState *gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
    678673        EngineState *retval;
    679674        SongLibrary temp;
     
    739734        retval->script_000 = retval->segMan->getScript(retval->segMan->getScriptSegment(0, SCRIPT_GET_DONT_LOAD));
    740735        retval->gc_countdown = GC_INTERVAL - 1;
    741736        retval->sys_strings_segment = retval->segMan->findSegmentByType(MEM_OBJ_SYS_STRINGS);
    742         retval->sys_strings = (SystemStrings *)GET_SEGMENT(*retval->segMan, retval->sys_strings_segment, MEM_OBJ_SYS_STRINGS);
     737        retval->systemStrings = (SystemStrings *)GET_SEGMENT(*retval->segMan, retval->sys_strings_segment, MEM_OBJ_SYS_STRINGS);
    743738
    744         // Restore system strings
    745         SystemString *str;
    746 
    747         // First, pad memory
    748         for (int i = 0; i < SYS_STRINGS_MAX; i++) {
    749                 str = &retval->sys_strings->strings[i];
    750                 char *data = (char *)str->value;
    751                 if (data) {
    752                         str->value = (reg_t *)calloc(str->max_size + 1, sizeof(reg_t));
    753                         strncpy((char *)str->value, data, str->max_size + 1);           // FIXME -- strncpy or internal_stringfrag_strncpy ?
    754                         free(data);
    755                 }
    756         }
    757 
    758         str = &retval->sys_strings->strings[SYS_STRING_SAVEDIR];
    759         internal_stringfrag_strncpy(s, str->value, s->sys_strings->strings[SYS_STRING_SAVEDIR].value, str->max_size);
    760         str->value[str->max_size - 1].segment = s->string_frag_segment; // Make sure to terminate
    761         str->value[str->max_size - 1].offset &= 0xff00; // Make sure to terminate
    762 
    763739        // Time state:
    764740        retval->last_wait_time = g_system->getMillis();
    765741        retval->game_start_time = g_system->getMillis() - retval->game_time * 1000;
  • engine/savegame.h

     
    3636struct EngineState;
    3737
    3838enum {
    39         CURRENT_SAVEGAME_VERSION = 10,
     39        CURRENT_SAVEGAME_VERSION = 11,
    4040        MINIMUM_SAVEGAME_VERSION = 9
    4141};
    4242
  • engine/seg_manager.cpp

     
    769769        return (SystemStrings *)allocSegment(MEM_OBJ_SYS_STRINGS, segid);
    770770}
    771771
    772 SegmentId SegManager::allocateStringFrags() {
    773         SegmentId segid;
    774 
    775         allocSegment(MEM_OBJ_STRING_FRAG, &segid);
    776 
    777         return segid;
    778 }
    779 
    780772uint16 SegManager::validateExportFunc(int pubfunct, SegmentId seg) {
    781773        Script *scr = getScript(seg);
    782774        if (scr->exports_nr <= pubfunct) {
  • engine/seg_manager.h

     
    239239        SystemStrings *allocateSysStrings(SegmentId *segid);
    240240
    241241
    242         // 5. System Strings
    243 
    244         /**
    245          * Allocates a string fragments segment
    246          * See also stringfrag.h
    247          * @return      Segment ID to use for string fragments
    248          */
    249         SegmentId allocateStringFrags();
    250 
    251 
    252242        // 6, 7. Lists and Nodes
    253243
    254244        /**
  • engine/state.cpp

     
    9999        bp_list = 0;
    100100        have_bp = 0;
    101101        sys_strings_segment = 0;
    102         sys_strings = 0;
    103         string_frag_segment = 0;
    104102
    105103        memset(parser_nodes, 0, sizeof(parser_nodes));
    106104
  • engine/state.h

     
    285285
    286286        /* System strings */
    287287        SegmentId sys_strings_segment;
    288         SystemStrings *sys_strings;
     288        SystemStrings *systemStrings;
    289289
    290         SegmentId string_frag_segment;
    291 
    292290        /* Parser data: */
    293291        parse_tree_node_t parser_nodes[VOCAB_TREE_NODES]; /**< The parse tree */
    294292
  • engine/stringfrag.cpp

     
    1 /* ScummVM - Graphic Adventure Engine
    2  *
    3  * ScummVM is the legal property of its developers, whose names
    4  * are too numerous to list here. Please refer to the COPYRIGHT
    5  * file distributed with this source distribution.
    6  *
    7  * This program is free software; you can redistribute it and/or
    8  * modify it under the terms of the GNU General Public License
    9  * as published by the Free Software Foundation; either version 2
    10  * of the License, or (at your option) any later version.
    11 
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15  * GNU General Public License for more details.
    16 
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program; if not, write to the Free Software
    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    20  *
    21  * $URL$
    22  * $Id$
    23  *
    24  */
    25 
    26 #include "sci/engine/state.h"
    27 #include "sci/engine/kernel.h"
    28 
    29 namespace Sci {
    30 
    31 /*
    32 The following is an email Lars wrote mid march and which explains a little
    33 bit about system strings. I paste it here for future reference. Some of this
    34 could possible be turned into documentation for the strings frags code...
    35 */
    36 
    37 /*
    38 Max Horn wrote:
    39 > Basically, saving the reg_t "array" (?) in the SystemString struct (see
    40 > sync_SystemString in engine/savegame.cpp) seems like a bad hack that will
    41 > result in breakage...
    42 
    43 The short explanation is that the casts _will_ go away, but that the
    44 system strings, too, will become stringfrag-based eventually.
    45 
    46 The long version requires a bit of background: During the SCI01
    47 timeframe, a Memory() call was added which does not really play well
    48 with the Glutton architecture (as well as having the potential for
    49 nasty game bugs - it allows games to write to any part of the
    50 heap). The same memory call is used for modification of strings and
    51 integer arrays (as is direct array indexing). From a formal point of
    52 view, the use of either of these for string handling is wrong. There
    53 exist string APIs that should be used instead. But things being as
    54 they are, we need to be able to tell the two types apart
    55 somehow. Currently, we have a heuristic in there which doesn't always
    56 work (it breaks LSL5 password protection, for one thing) - the string
    57 frags code is intended to replace this heuristic, but requires
    58 changing the argument parsing of every kernel function that uses
    59 strings. This _will_ cause regressions, and for that reason I only
    60 changed the interface definitions, not the implementation. As I wrote
    61 to Willem the other day, I was trying to commit as much of the
    62 stringfrag code as I could without breaking existing code, and isolate
    63 the breakage to a later set of commits.
    64 
    65 Also, a little background on the system strings. In Sierra SCI, the
    66 heap is stored in the interpreter's data segment and is not precisely
    67 64K in size - but rather 64K minus the size of the interpreter's
    68 static data. However, the script code does have read/write access
    69 to this static data. The strings that we store in the system strings
    70 table are stored in static data in Sierra SCI. We have only two at
    71 this point:
    72 
    73 1. The savegame directory
    74 2. Parser error handling
    75 
    76 2) doesn't actually need to be saved, because not only is the variable
    77 only used during error handling, but the routine in question is called
    78 re-entrantly by the kernel function - and not even the old save system
    79 supports saving in that kind of situation, much less Sierra SCI. On
    80 the other hand, the scripts retain a pointer to 1) which needs to
    81 remain valid across saves.
    82 */
    83 
    84 #define STRINGFRAG_SEGMENT s->string_frag_segment
    85 // #define STRINGFRAG_SEGMENT 0xffff
    86 
    87 static int internal_is_valid_stringfrag(EngineState *s, reg_t *buffer) {
    88         if (buffer == NULL)
    89                 return 0;
    90 
    91         while ((buffer->offset & 0xff00) != 0 &&
    92                (buffer->offset & 0x00ff) != 0) {
    93                 if (buffer->segment != STRINGFRAG_SEGMENT)
    94                         return 0;
    95                 buffer++;
    96         }
    97 
    98         if (buffer->segment != STRINGFRAG_SEGMENT) {
    99                 return 0;
    100         }
    101 
    102         return 1;
    103 }
    104 
    105 int is_valid_stringfrag(EngineState *s, reg_t pos) {
    106         reg_t *buffer = s->segMan->derefRegPtr(pos, 1);
    107 
    108         return internal_is_valid_stringfrag(s, buffer);
    109 }
    110 
    111 static int internal_stringfrag_length(EngineState *s, reg_t *buffer) {
    112         int result = 0;
    113 
    114         if (buffer == NULL) {
    115 //      error("Error: Invalid stringfrag handle");
    116                 return 0;
    117         }
    118 
    119         while ((buffer->offset & 0xff00) != 0 &&
    120                (buffer->offset & 0x00ff) != 0) {
    121                 if (buffer->segment != STRINGFRAG_SEGMENT) {
    122 //          error("Error: Invalid stringfrag handle");
    123                         return 0;
    124                 }
    125 
    126                 result += 2;
    127                 buffer++;
    128         }
    129 
    130         if (buffer->segment != STRINGFRAG_SEGMENT) {
    131                 error("Error: Invalid stringfrag handle");
    132                 return 0;
    133         }
    134 
    135         if ((buffer->offset & 0xff00) != 0)
    136                 result++;
    137         return result;
    138 }
    139 
    140 int stringfrag_length(EngineState *s, reg_t pos) {
    141         reg_t *buffer = s->segMan->derefRegPtr(pos, 1);
    142 
    143         return internal_stringfrag_length(s, buffer);
    144 }
    145 
    146 static void internal_stringfrag_to_ascii(EngineState *s, reg_t *buffer) {
    147         int str_length = internal_stringfrag_length(s, buffer);
    148         char *temp = (char *)malloc(str_length + 1);
    149         int i = 0;
    150 
    151         while ((buffer->offset & 0xff00) != 0 &&
    152                (buffer->offset & 0x00ff) != 0) {
    153                 temp[i] = (buffer->offset & 0xff00) >> 8;
    154                 if (temp[i] != 0)
    155                         temp[i+1] = buffer->offset & 0xff;
    156                 i += 2;
    157                 buffer++;
    158         }
    159 
    160         if ((buffer->offset & 0xff00) != 0) {
    161                 temp[i] = (buffer->offset & 0xff00) >> 8;
    162                 temp[i+1] = 0;
    163         } else {
    164                 temp[i] = 0;
    165         }
    166 
    167         strcpy((char *)buffer, temp);
    168         free(temp);
    169 }
    170 
    171 void stringfrag_to_ascii(EngineState *s, reg_t pos) {
    172         reg_t *buffer = s->segMan->derefRegPtr(pos, 1);
    173 
    174         internal_stringfrag_to_ascii(s, buffer);
    175 }
    176 
    177 static void internal_ascii_to_stringfrag(EngineState *s, reg_t *buffer) {
    178         int str_length = strlen((char *)buffer);
    179         int words = str_length % 2 ? (str_length+2)/2 : (str_length + 1)/2;
    180         char *temp = (char *)malloc(str_length + 1);
    181 
    182         strcpy(temp, (char *)buffer);
    183         for (int i = 0; i < words; i++) {
    184                 buffer[i].segment = STRINGFRAG_SEGMENT;
    185                 buffer[i].offset = temp[i*2];
    186                 if (temp[i*2])
    187                         buffer[i].offset |= temp[i*2+1];
    188         }
    189 
    190         free(temp);
    191 }
    192 
    193 void ascii_to_stringfrag(EngineState *s, reg_t pos) {
    194         reg_t *buffer = s->segMan->derefRegPtr(pos, 1);
    195 
    196         internal_ascii_to_stringfrag(s, buffer);
    197 }
    198 
    199 static void internal_stringfrag_append_char(EngineState *s, reg_t *buffer, unsigned char c) {
    200         while ((buffer->offset & 0xff00) != 0 &&
    201                (buffer->offset & 0x00ff) != 0)
    202                 buffer++;
    203 
    204         if ((buffer->offset & 0xff00) == 0) {
    205                 buffer->offset = c << 8;
    206         } else {
    207                 if ((buffer->offset & 0x00ff) == 0) {
    208                         buffer->offset |= c;
    209                         buffer++;
    210                         buffer->segment = STRINGFRAG_SEGMENT;
    211                         buffer->offset = 0;
    212                 }
    213         }
    214 }
    215 
    216 void stringfrag_append_char(EngineState *s, reg_t pos, unsigned char c) {
    217         reg_t *buffer = s->segMan->derefRegPtr(pos, 1);
    218 
    219         internal_stringfrag_append_char(s, buffer, c);
    220 }
    221 
    222 void stringfrag_setchar(reg_t *buffer, int pos, int offset, unsigned char c) {
    223         switch (offset) {
    224         case 0 :
    225                 buffer[pos].offset = (buffer[pos].offset & 0x00ff) | (c << 8);
    226                 break;
    227         case 1 :
    228                 buffer[pos].offset = (buffer[pos].offset & 0xff00) | c;
    229                 break;
    230         }
    231 }
    232 
    233 unsigned char stringfrag_getchar(reg_t *buffer, int pos, int offset) {
    234         switch (offset) {
    235         case 0 :
    236                 return buffer[pos].offset >> 8;
    237         case 1 :
    238                 return buffer[pos].offset & 0xff;
    239         default:
    240                 return 0; // FIXME: Is it safe to return "0" here?
    241         }
    242 }
    243 
    244 void stringfrag_memmove(EngineState *s, reg_t *buffer, int sourcepos, int destpos, int count) {
    245         /* Some of these values are not used yet. There are a couple
    246            of cases that we could implement faster if the need arises, in
    247            which case we would most certainly need these. */
    248         int source_begin_pos = sourcepos/2;
    249         int source_begin_offset = sourcepos%2;
    250         int source_end_pos = (sourcepos+count-1)/2;
    251         int source_end_offset = (sourcepos+count-1)%2;
    252 
    253         int dest_begin_pos = destpos/2;
    254         int dest_begin_offset = destpos%2;
    255         int dest_end_pos = (destpos+count-1)/2;
    256         int dest_end_offset = (destpos+count-1)%2;
    257 
    258         if (sourcepos < destpos) {
    259                 for (int n = count-1; n >= 0; n--) {
    260                         buffer[dest_end_pos].segment = STRINGFRAG_SEGMENT;
    261                         stringfrag_setchar(buffer, dest_end_pos, dest_end_offset,
    262                                            stringfrag_getchar(buffer, source_end_pos, source_end_offset));
    263                         if (source_end_offset ^= 1)
    264                                 source_end_pos --;
    265                         if (dest_end_offset ^= 1)
    266                                 dest_end_pos --;
    267                 }
    268         } else {
    269                 for (int n = 0; n < count; n++) {
    270                         buffer[dest_begin_pos].segment = STRINGFRAG_SEGMENT;
    271                         stringfrag_setchar(buffer, dest_begin_pos, dest_begin_offset,
    272                                            stringfrag_getchar(buffer, source_begin_pos, source_begin_offset));
    273                         if (!(source_begin_offset ^= 1))
    274                                 source_begin_pos ++;
    275                         if (!(dest_begin_offset ^= 1))
    276                                 dest_begin_pos ++;
    277                 }
    278         }
    279 }
    280 
    281 static void internal_stringfrag_insert_char(EngineState *s, reg_t *buffer, int p, unsigned char c) {
    282         reg_t *save = buffer + p/2;
    283         reg_t *seeker = buffer + p/2;
    284         int restore_nul_offset;
    285         int restore_nul_pos;
    286         int len = internal_stringfrag_length(s, buffer);
    287 
    288         while ((seeker->offset & 0xff00) != 0 &&
    289                (seeker->offset & 0x00ff) != 0)
    290                 seeker++;
    291 
    292         /* The variables restore_null_offset and restore_null_pos will
    293            indicate where the NUL character should be PUT BACK after
    294            inserting c, as this operation might overwrite the NUL. */
    295         if (seeker->offset & 0xff00) {
    296                 restore_nul_offset = 1;
    297                 restore_nul_pos = 0;
    298         } else {
    299                 restore_nul_offset = 0;
    300                 restore_nul_pos = 1;
    301         }
    302 
    303         if (seeker-save == 0) { // So p is at the end, use fast method
    304                 internal_stringfrag_append_char(s, seeker, c);
    305                 return;
    306         }
    307 
    308         stringfrag_memmove(s, buffer, p, p+1, len-p);
    309         stringfrag_setchar(buffer, p/2, p%2, c);
    310         stringfrag_setchar(seeker, restore_nul_pos, restore_nul_offset, 0);
    311 }
    312 
    313 void stringfrag_insert_char(EngineState *s, reg_t pos, int p, unsigned char c) {
    314         reg_t *buffer = s->segMan->derefRegPtr(pos, 1);
    315 
    316         internal_stringfrag_insert_char(s, buffer, p, c);
    317 }
    318 
    319 static void internal_stringfrag_delete_char(EngineState *s, reg_t *buffer, int p) {
    320         //reg_t *save = buffer + p;
    321         reg_t *seeker = buffer + p;
    322         int restore_nul_offset;
    323         int restore_nul_pos;
    324         int len = internal_stringfrag_length(s, buffer);
    325 
    326         while ((seeker->offset & 0xff00) != 0 &&
    327                (seeker->offset & 0x00ff) != 0)
    328                 seeker++;
    329 
    330         /* The variables restore_null_offset and restore_null_pos will
    331            indicate where the NUL character should be PUT BACK after
    332            deletion, as this operation might overwrite the NUL. */
    333         if (seeker->offset & 0xff00) {
    334                 restore_nul_offset = 1;
    335                 restore_nul_pos = -1;
    336         } else {
    337                 restore_nul_offset = 0;
    338                 restore_nul_pos = 0;
    339         }
    340 
    341         stringfrag_memmove(s, buffer, p, p-1, len-p);
    342         stringfrag_setchar(seeker, restore_nul_pos, restore_nul_offset, 0);
    343 }
    344 
    345 void stringfrag_delete_char(EngineState *s, reg_t pos, int p) {
    346         reg_t *buffer = s->segMan->derefRegPtr(pos, 1);
    347 
    348         internal_stringfrag_delete_char(s, buffer, p);
    349 }
    350 
    351 void internal_stringfrag_strcpy(EngineState *s, reg_t *dest, reg_t *src) {
    352         while ((src->offset & 0xff00) != 0 &&
    353                (src->offset & 0x00ff) != 0) {
    354                 *dest = *src;
    355                 dest++;
    356                 src++;
    357         }
    358 
    359         *dest = *src;
    360 }
    361 
    362 void stringfrag_strcpy(EngineState *s, reg_t dest, reg_t src) {
    363         reg_t *destbuf = s->segMan->derefRegPtr(dest, 1);
    364         reg_t *srcbuf = s->segMan->derefRegPtr(src, 1);
    365 
    366         internal_stringfrag_strcpy(s, destbuf, srcbuf);
    367 }
    368 
    369 void internal_stringfrag_strncpy(EngineState *s, reg_t *dest, reg_t *src, int len) {
    370         while ((src->offset & 0xff00) != 0 &&
    371                (src->offset & 0x00ff) != 0 &&
    372                (len -= 2) > 1) {
    373                 *dest = *src;
    374                 dest++;
    375                 src++;
    376         }
    377 
    378         for (; len > 1; len -= 2) {
    379                 dest->segment = STRINGFRAG_SEGMENT;
    380                 dest->offset = 0;
    381                 len -= 2;
    382         }
    383 
    384         if (len == 1)
    385                 stringfrag_setchar(dest, 0, 0, 0);
    386 
    387         *dest = *src;
    388 }
    389 
    390 void stringfrag_strncpy(EngineState *s, reg_t dest, reg_t src, int len) {
    391         reg_t *destbuf = s->segMan->derefRegPtr(dest, 1);
    392         reg_t *srcbuf = s->segMan->derefRegPtr(src, 1);
    393 
    394         internal_stringfrag_strncpy(s, destbuf, srcbuf, len);
    395 }
    396 
    397 int internal_stringfrag_strcmp(EngineState *s, reg_t *s1, reg_t *s2) {
    398         int c1, c2;
    399         while (1) {
    400                 c1 = (uint16)(s1->offset & 0xff00);
    401                 c2 = (uint16)(s2->offset & 0xff00);
    402                 if (c1 != c2)           // We found a difference
    403                         return c1 - c2;
    404                 else if (c1 == 0)       // Both strings ended
    405                         return 0;
    406 
    407                 c1 = (uint16)(s1->offset & 0x00ff);
    408                 c2 = (uint16)(s2->offset & 0x00ff);
    409                 if (c1 != c2)           // We found a difference
    410                         return c1 - c2;
    411                 else if (c1 == 0)       // Both strings ended
    412                         return 0;
    413         }
    414 
    415         return 0;
    416 }
    417 
    418 void stringfrag_strcmp(EngineState *s, reg_t s1, reg_t s2) {
    419         reg_t *s1buf = s->segMan->derefRegPtr(s1, 1);
    420         reg_t *s2buf = s->segMan->derefRegPtr(s2, 1);
    421 
    422         internal_stringfrag_strcmp(s, s1buf, s2buf);
    423 }
    424 
    425 int internal_stringfrag_strncmp(EngineState *s, reg_t *s1, reg_t *s2, int len) {
    426         int c1, c2;
    427         while (len) {
    428                 if (len--)
    429                         return 0;
    430                 c1 = (uint16)(s1->offset & 0xff00);
    431                 c2 = (uint16)(s2->offset & 0xff00);
    432                 if (c1 != c2)           // We found a difference
    433                         return c1 - c2;
    434                 else if (c1 == 0)       // Both strings ended
    435                         return 0;
    436 
    437                 if (len--)
    438                         return 0;
    439 
    440                 c1 = (uint16)(s1->offset & 0x00ff);
    441                 c2 = (uint16)(s2->offset & 0x00ff);
    442                 if (c1 != c2)           // We found a difference
    443                         return c1 - c2;
    444                 else if (c1 == 0)       // Both strings ended
    445                         return 0;
    446         }
    447 
    448         return 0;
    449 }
    450 
    451 void stringfrag_strncmp(EngineState *s, reg_t s1, reg_t s2, int len) {
    452         reg_t *s1buf = s->segMan->derefRegPtr(s1, 1);
    453         reg_t *s2buf = s->segMan->derefRegPtr(s2, 1);
    454 
    455         internal_stringfrag_strncmp(s, s1buf, s2buf, len);
    456 }
    457 
    458 } // end of namespace Sci
  • module.mk

     
    3333        engine/scriptdebug.o \
    3434        engine/seg_manager.o \
    3535        engine/static_selectors.o \
    36         engine/stringfrag.o \
    3736        engine/state.o \
    3837        engine/vm.o \
    3938        gfx/font.o \
  • sci.cpp

     
    153153
    154154        // Set the savegame dir (actually, we set it to a fake value,
    155155        // since we cannot let the game control where saves are stored)
    156         script_set_gamestate_save_dir(_gamestate, "/");
     156        _gamestate->systemStrings->strings[SYS_STRING_SAVEDIR] = "/";
    157157
    158158        GfxState gfx_state;
    159159        _gamestate->gfx_state = &gfx_state;