Skip to content

Commit f2eb99a

Browse files
committed
[[ Bug 17690 ]] Move file header constants to stackfileformat.h. Create functions for header parsing & generating.
1 parent 844395b commit f2eb99a

8 files changed

Lines changed: 193 additions & 124 deletions

File tree

engine/engine-sources.gypi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@
294294
'src/stack3.cpp',
295295
'src/stackcache.cpp',
296296
'src/stacke.cpp',
297+
'src/stackfileformat.cpp',
297298
'src/stacklst.cpp',
298299
'src/stackview.cpp',
299300
'src/styledtext.cpp',

engine/src/cmdss.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
4747
#include "exec.h"
4848
#include "syntax.h"
4949
#include "variable.h"
50+
#include "stackfileformat.h"
5051

5152
MCCompact::~MCCompact()
5253
{
@@ -448,7 +449,7 @@ MCStack *MCGo::findstack(MCExecContext &ctxt, MCStringRef p_value, Chunk_term et
448449
{
449450
MCStack *sptr = NULL;
450451
uint4 offset;
451-
if (MCStringFirstIndexOf(p_value, MCSTR(SIGNATURE), 0, kMCCompareExact, offset)
452+
if (MCStringFirstIndexOf(p_value, MCSTR(kMCStackFileMetaCardSignature), 0, kMCCompareExact, offset)
452453
|| (MCStringGetLength(p_value) > 8 && MCStringBeginsWithCString(p_value, (char_t*)"REVO", kMCCompareExact)))
453454
{
454455
char_t* t_cstring_value;

engine/src/dispatch.cpp

Lines changed: 25 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -72,20 +72,6 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
7272

7373
MCImage *MCDispatch::imagecache;
7474

75-
#define VERSION_OFFSET 11
76-
77-
#define HEADERSIZE 255
78-
static char header[HEADERSIZE] = "#!/bin/sh\n# MetaCard 2.4 stack\n# The following is not ASCII text,\n# so now would be a good time to q out of more\f\nexec mc $0 \"$@\"\n";
79-
80-
#define NEWHEADERSIZE 8
81-
#define HEADERPREFIXSIZE 4
82-
static const char *newheader = "REVO2700";
83-
static const char *newheader5500 = "REVO5500";
84-
static const char *newheader7000 = "REVO7000";
85-
static const char *newheader8000 = "REVO8000";
86-
87-
#define MAX_STACKFILE_VERSION 8000
88-
8975
////////////////////////////////////////////////////////////////////////////////
9076

9177
MCPropertyInfo MCDispatch::kProperties[] =
@@ -431,66 +417,33 @@ Boolean MCDispatch::openenv(MCStringRef sname, MCStringRef env,
431417

432418
IO_stat readheader(IO_handle& stream, uint32_t& r_version)
433419
{
434-
char tnewheader[NEWHEADERSIZE];
435-
if (IO_read(tnewheader, NEWHEADERSIZE, stream) == IO_NORMAL)
436-
{
437-
// AL-2014-10-27: [[ Bug 12558 ]] Check for valid header prefix
438-
if (strncmp(tnewheader, "REVO", HEADERPREFIXSIZE) == 0)
439-
{
440-
// The header version can now consist of any alphanumeric characters
441-
// They map to numbers as follows:
442-
// 0-9 -> 0-9
443-
// A-Z -> 10-35
444-
// a-z -> 36-61
445-
uint1 versionnum[4];
446-
for (uint1 i = 0; i < 4; i++)
447-
{
448-
char t_char = tnewheader[i + 4];
449-
if ('0' <= t_char && t_char <= '9')
450-
versionnum[i] = (uint1)(t_char - '0');
451-
else if ('A' <= t_char && t_char <= 'Z')
452-
versionnum[i] = (uint1)(t_char - 'A' + 10);
453-
else if ('a' <= t_char && t_char <= 'z')
454-
versionnum[i] = (uint1)(t_char - 'a' + 36);
455-
else
456-
return IO_ERROR;
457-
}
458-
459-
// Future file format versions will always still compare greater than MAX_STACKFILE_VERSION,
460-
// so it is ok that r_version does not accurately reflect future version values.
461-
// TODO: change this, and comparisons for version >= 7000 / 5500, etc
462-
r_version = versionnum[0] * 1000;
463-
r_version += versionnum[1] * 100;
464-
r_version += versionnum[2] * 10;
465-
r_version += versionnum[3];
466-
}
467-
else
420+
char tnewheader[kMCStackFileVersionStringLength];
421+
if (IO_read(tnewheader, kMCStackFileVersionStringLength, stream) != IO_NORMAL)
422+
return IO_ERROR;
423+
424+
// AL-2014-10-27: [[ Bug 12558 ]] Check for valid header prefix
425+
if (!MCStackFileParseVersionNumber(tnewheader, r_version))
426+
{
427+
char theader[kMCStackFileMetaCardVersionStringLength + 1];
428+
theader[kMCStackFileMetaCardVersionStringLength] = '\0';
429+
uint4 offset;
430+
strncpy(theader, tnewheader, kMCStackFileVersionStringLength);
431+
if (IO_read(theader + kMCStackFileVersionStringLength, kMCStackFileMetaCardVersionStringLength - kMCStackFileVersionStringLength, stream) == IO_NORMAL
432+
&& MCU_offset(kMCStackFileMetaCardSignature, theader, offset))
468433
{
469-
char theader[HEADERSIZE + 1];
470-
theader[HEADERSIZE] = '\0';
471-
uint4 offset;
472-
strncpy(theader, tnewheader, NEWHEADERSIZE);
473-
if (IO_read(theader + NEWHEADERSIZE, HEADERSIZE - NEWHEADERSIZE, stream) == IO_NORMAL
474-
&& MCU_offset(SIGNATURE, theader, offset))
434+
if (theader[offset - 1] != '\n' || theader[offset - 2] == '\r')
475435
{
476-
if (theader[offset - 1] != '\n' || theader[offset - 2] == '\r')
477-
{
478-
MCresult->sets("stack was corrupted by a non-binary file transfer");
479-
return IO_ERROR;
480-
}
481-
482-
r_version = (theader[offset + VERSION_OFFSET] - '0') * 1000;
483-
r_version += (theader[offset + VERSION_OFFSET + 2] - '0') * 100;
484-
}
485-
else
436+
MCresult->sets("stack was corrupted by a non-binary file transfer");
486437
return IO_ERROR;
438+
}
439+
440+
r_version = (theader[offset + kMCStackFileMetaCardSignatureLength] - '0') * 1000;
441+
r_version += (theader[offset + kMCStackFileMetaCardSignatureLength + 2] - '0') * 100;
487442
}
443+
else
444+
return IO_ERROR;
488445
}
489-
else
490-
{
491-
// Could not read header
492-
return IO_ERROR;
493-
}
446+
494447
return IO_NORMAL;
495448
}
496449

@@ -597,7 +550,7 @@ IO_stat MCDispatch::doreadfile(MCStringRef p_openpath, MCStringRef p_name, IO_ha
597550
// MW-2014-09-30: [[ ScriptOnlyStack ]] First see if it is a binary stack.
598551
if (readheader(stream, version) == IO_NORMAL)
599552
{
600-
if (version > MAX_STACKFILE_VERSION)
553+
if (version > kMCStackFileFormatCurrentVersion)
601554
{
602555
MCresult->sets("stack was produced by a newer version");
603556
return checkloadstat(IO_ERROR);
@@ -995,7 +948,7 @@ IO_stat MCDispatch::savestack(MCStack *sptr, const MCStringRef p_fname, uint32_t
995948
}
996949
else
997950
{
998-
/* If no version was specified, assume that 8.0 format was requested */
951+
/* If no version was specified, assume that current format was requested */
999952
if (UINT32_MAX == p_version)
1000953
{
1001954
p_version = kMCStackFileFormatCurrentVersion;
@@ -1148,16 +1101,7 @@ IO_stat MCDispatch::dosavestack(MCStack *sptr, const MCStringRef p_fname, uint32
11481101
// MW-2012-03-04: [[ StackFile5500 ]] Work out what header to emit, and the size.
11491102
const char *t_header;
11501103
uint32_t t_header_size;
1151-
if (p_version >= kMCStackFileFormatVersion_8_0)
1152-
t_header = newheader8000, t_header_size = 8;
1153-
else if (p_version >= kMCStackFileFormatVersion_7_0)
1154-
t_header = newheader7000, t_header_size = 8;
1155-
else if (p_version >= kMCStackFileFormatVersion_5_5)
1156-
t_header = newheader5500, t_header_size = 8;
1157-
else if (p_version >= kMCStackFileFormatVersion_2_7)
1158-
t_header = newheader, t_header_size = 8;
1159-
else
1160-
t_header = header, t_header_size = HEADERSIZE;
1104+
MCStackFileGetHeaderForVersion(p_version, t_header, t_header_size);
11611105

11621106
if (IO_write(t_header, sizeof(char), t_header_size, stream) != IO_NORMAL
11631107
|| IO_write_uint1(CHARSET, stream) != IO_NORMAL)

engine/src/exec-interface2.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2405,7 +2405,7 @@ static MCStack *MCInterfaceTryToEvalBinaryStack(MCStringRef p_data, bool& r_bina
24052405
t_stack = nil;
24062406
t_binary_fail = false;
24072407

2408-
if (MCStringFirstIndexOf(p_data, MCSTR(SIGNATURE), 0, kMCCompareExact, offset) && (MCStringGetLength(p_data) > 8 && MCStringBeginsWithCString(p_data, (const char_t *)"REVO", kMCCompareExact)))
2408+
if (MCStringFirstIndexOf(p_data, MCSTR(kMCStackFileMetaCardSignature), 0, kMCCompareExact, offset) && (MCStringGetLength(p_data) > 8 && MCStringBeginsWithCString(p_data, (const char_t *)"REVO", kMCCompareExact)))
24092409
{
24102410
char_t* t_string;
24112411
uindex_t t_length;
@@ -2482,7 +2482,7 @@ void MCInterfaceEvalStackByValue(MCExecContext& ctxt, MCValueRef p_value, MCObje
24822482
{
24832483
uint4 offset;
24842484

2485-
if (MCStringFirstIndexOf((MCStringRef)p_value, MCSTR(SIGNATURE), 0, kMCCompareExact, offset) && MCStringGetLength((MCStringRef)p_value) > 8 && MCStringBeginsWithCString((MCStringRef)p_value, (const char_t *)"REVO", kMCCompareExact))
2485+
if (MCStringFirstIndexOf((MCStringRef)p_value, MCSTR(kMCStackFileMetaCardSignature), 0, kMCCompareExact, offset) && MCStringGetLength((MCStringRef)p_value) > 8 && MCStringBeginsWithCString((MCStringRef)p_value, (const char_t *)"REVO", kMCCompareExact))
24862486
{
24872487
MCInterfaceEvalBinaryStackAsObject(ctxt, (MCStringRef)p_value, r_stack);
24882488
return;

engine/src/filedefs.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
2222

2323
#include "typedefs.h"
2424

25-
#define SIGNATURE "# MetaCard "
26-
2725
#define READ_PIPE_SIZE 16384
2826

2927
#define SAVE_ENCRYPTED 0x80000000

engine/src/pickle.cpp

Lines changed: 27 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
4646
#include "stacksecurity.h"
4747
#include "widget.h"
4848

49+
#include "stackfileformat.h"
50+
4951
///////////////////////////////////////////////////////////////////////////////
5052
//
5153
// The MCPickleContext structure is an opaque type used by the state-based
@@ -232,8 +234,13 @@ void MCObject::continuepickling(MCPickleContext *p_context, MCObject *p_object,
232234
uint4 t_chunk_start;
233235
if (p_object -> haswidgets())
234236
{
237+
const char *t_header;
238+
uint32_t t_header_size;
239+
240+
MCStackFileGetHeaderForVersion(kMCStackFileFormatCurrentVersion, t_header, t_header_size);
241+
235242
if (t_stat == IO_NORMAL)
236-
t_stat = IO_write("REVO8000", 8, 1, t_stream);
243+
t_stat = IO_write(t_header, t_header_size, 1, t_stream);
237244

238245
// Write the space for the chunk size field
239246
if (t_stat == IO_NORMAL)
@@ -244,7 +251,7 @@ void MCObject::continuepickling(MCPickleContext *p_context, MCObject *p_object,
244251
t_chunk_start = MCS_tell(t_stream);
245252

246253
if (t_stat == IO_NORMAL)
247-
t_stat = pickle_object_to_stream(t_stream, 8000, p_object, p_part);
254+
t_stat = pickle_object_to_stream(t_stream, kMCStackFileFormatCurrentVersion, p_object, p_part);
248255
}
249256
else
250257
{
@@ -267,10 +274,10 @@ void MCObject::continuepickling(MCPickleContext *p_context, MCObject *p_object,
267274
// out the 5.5 and 7.0 versions.
268275
if (t_stat == IO_NORMAL && p_context -> include_legacy)
269276
{
270-
t_stat = pickle_object_to_stream(t_stream, 5500, p_object, p_part);
277+
t_stat = pickle_object_to_stream(t_stream, kMCStackFileFormatVersion_5_5, p_object, p_part);
271278

272279
if (t_stat == IO_NORMAL)
273-
pickle_object_to_stream(t_stream, 7000, p_object, p_part);
280+
pickle_object_to_stream(t_stream, kMCStackFileFormatVersion_7_0, p_object, p_part);
274281
}
275282
}
276283

@@ -502,33 +509,23 @@ MCObject *MCObject::unpickle(MCDataRef p_data, MCStack *p_stack)
502509

503510
while(t_length > 0 && t_success)
504511
{
505-
bool t_8000_only;
506-
t_8000_only = false;
507-
bool t_7000_only;
508-
t_7000_only = false;
509-
bool t_5500_only;
510-
t_5500_only = false;
511-
512512
if (t_success)
513513
t_success = t_length >= 12;
514-
514+
515+
uint32_t t_version;
516+
t_version = 0;
517+
if (t_success)
518+
t_success = MCStackFileParseVersionNumber(t_buffer, t_version);
519+
520+
// version should be 2.7 or greater
515521
if (t_success)
516522
{
517-
// AL-2014-02-14: [[ UnicodeFileFormat ]] If the header is 7.0, then there
518-
// won't be a 2.7 version before it.
519-
if (memcmp(t_buffer, "REVO8000", 8) == 0)
520-
t_8000_only = true;
521-
else if (memcmp(t_buffer, "REVO7000", 8) == 0)
522-
t_7000_only = true;
523-
else if (memcmp(t_buffer, "REVO5500", 8) == 0)
524-
t_5500_only = true;
525-
else if (memcmp(t_buffer, "REVO2700", 8) != 0)
526-
t_success = false;
523+
t_success = t_version >= kMCStackFileFormatVersion_2_7 && t_version <= kMCStackFileFormatCurrentVersion;
527524

528-
t_buffer += 8;
529-
t_length -= 8;
525+
t_buffer += kMCStackFileVersionStringLength;
526+
t_length -= kMCStackFileVersionStringLength;
530527
}
531-
528+
532529
uint4 t_chunk_length;
533530
t_chunk_length = 0;
534531
if (t_success)
@@ -552,33 +549,26 @@ MCObject *MCObject::unpickle(MCDataRef p_data, MCStack *p_stack)
552549
}
553550

554551
// AL-2014-02-14: [[ UnicodeFileFormat ]] Unpickle the first version in the chunk.
555-
// If there is no 2.7, then the version will be 7.0; otherwise it is the
552+
// If there is no 2.7, then there will be a single version; otherwise it is the
556553
// 2.7 version preceeding the 5.5 and 7.0 ones.
557554
MCObject *t_object;
558555
t_object = nil;
559556
if (t_success)
560-
{
561-
if (t_8000_only)
562-
t_success = unpickle_object_from_stream(t_stream, 8000, p_stack, t_object);
563-
else if (t_7000_only)
564-
t_success = unpickle_object_from_stream(t_stream, 7000, p_stack, t_object);
565-
else
566-
t_success = unpickle_object_from_stream(t_stream, t_5500_only ? 5500 : 2700, p_stack, t_object);
567-
}
557+
t_success = unpickle_object_from_stream(t_stream, t_version, p_stack, t_object);
568558

569559
// AL-2014-02-14: [[ UnicodeFileFormat ]] If the header was 2.7, then there could
570560
// be 5.5 and 7.0 versions following it. So attempt to unpickle second and third
571561
// versions, and use them if present.
572-
if (t_success && !t_8000_only && !t_7000_only && !t_5500_only)
562+
if (t_success && t_version == kMCStackFileFormatVersion_2_7)
573563
{
574564
MCObject *t_5500_object;
575-
if (unpickle_object_from_stream(t_stream, 5500, p_stack, t_5500_object))
565+
if (unpickle_object_from_stream(t_stream, kMCStackFileFormatVersion_5_5, p_stack, t_5500_object))
576566
{
577567
delete t_object;
578568
t_object = t_5500_object;
579569
}
580570
MCObject *t_7000_object;
581-
if (unpickle_object_from_stream(t_stream, 7000, p_stack, t_7000_object))
571+
if (unpickle_object_from_stream(t_stream, kMCStackFileFormatVersion_7_0, p_stack, t_7000_object))
582572
{
583573
delete t_object;
584574
t_object = t_7000_object;

0 commit comments

Comments
 (0)