From b623f5953691b2a0614e6f1f4def86bdbb9a4113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sat, 8 Aug 2020 11:53:00 +0200 Subject: New upstream version 5.2.0Beta2.1 --- app/bin/fileio.c | 963 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 639 insertions(+), 324 deletions(-) (limited to 'app/bin/fileio.c') diff --git a/app/bin/fileio.c b/app/bin/fileio.c index 4e2a21d..cb0c8de 100644 --- a/app/bin/fileio.c +++ b/app/bin/fileio.c @@ -33,12 +33,10 @@ #include #include #ifdef WINDOWS -#include -#include - //#if _MSC_VER >=1400 - // #define strdup _strdup - //#endif -#else + #include + #define W_OK (2) + #define access _access + #include #endif #include #include @@ -48,35 +46,52 @@ #include +#include + +#include "archive.h" #include "common.h" #include "compound.h" #include "cselect.h" #include "cundo.h" #include "custom.h" +#include "directory.h" #include "draw.h" #include "fileio.h" +#include "fcntl.h" #include "i18n.h" #include "layout.h" +#include "manifest.h" #include "messages.h" #include "misc.h" #include "param.h" +#include "include/paramfile.h" #include "paths.h" #include "track.h" #include "utility.h" #include "version.h" +#include "dynstring.h" + +#ifdef WINDOWS +#include "include/utf8convert.h" +#endif // WINDOWS /*#define TIME_READTRACKFILE*/ +#define COPYBLOCKSIZE 1024 + EXPORT const char * workingDir; EXPORT const char * libDir; -static char * customPath = NULL; -static char * customPathBak = NULL; +EXPORT wMenuList_p fileList_ml; EXPORT char * clipBoardN; +static coOrd paste_offset, cursor_offset; + +EXPORT wBool_t bExample = FALSE; +EXPORT wBool_t bReadOnly = FALSE; + -static int log_paramFile; #ifdef WINDOWS #define rename( F1, F2 ) Copyfile( F1, F2 ) @@ -151,20 +166,13 @@ RestoreLocale( char * locale ) EXPORT FILE * paramFile = NULL; char *paramFileName; EXPORT wIndex_t paramLineNum = 0; -EXPORT char paramLine[STR_LONG_SIZE]; +EXPORT char paramLine[STR_HUGE_SIZE]; EXPORT char * curContents; EXPORT char * curSubContents; -static long paramCheckSum; #define PARAM_DEMO (-1) -typedef struct { - char * name; - readParam_t proc; - } paramProc_t; -static dynArr_t paramProc_da; -#define paramProc(N) DYNARR_N( paramProc_t, paramProc_da, N ) - +dynArr_t paramProc_da; EXPORT void Stripcr( char * line ) { @@ -179,13 +187,6 @@ EXPORT void Stripcr( char * line ) *cp = '\0'; } -EXPORT void ParamCheckSumLine( char * line ) -{ - long mult=1; - while ( *line ) - paramCheckSum += (((long)(*line++))&0xFF)*(mult++); -} - EXPORT char * GetNextLine( void ) { if (!paramFile) { @@ -193,7 +194,12 @@ EXPORT char * GetNextLine( void ) return NULL; } if (fgets( paramLine, sizeof paramLine, paramFile ) == NULL) { - AbortProg( "Permature EOF on %s", paramFileName ); + sprintf( message, "INPUT ERROR: premature EOF on %s", paramFileName ); + wNoticeEx( NT_ERROR, message, _("Ok"), NULL ); + if ( paramFile ) { + fclose( paramFile ); + paramFile = NULL; + } } Stripcr( paramLine ); ParamCheckSumLine( paramLine ); @@ -234,9 +240,14 @@ EXPORT int InputError( } strcat( mp, _("\nDo you want to continue?") ); if (!(ret = wNoticeEx( NT_ERROR, message, _("Continue"), _("Stop") ))) { - if ( paramFile ) + if ( paramFile ) { fclose(paramFile); - paramFile = NULL; + paramFile = NULL; + } + if ( paramFileName ) { + free( paramFileName ); + paramFileName = NULL; + } } return ret; } @@ -251,6 +262,7 @@ EXPORT void SyntaxError( TRUE, event, actual, expected ); } + /** * Parse a line in XTrackCAD's file format * @@ -258,6 +270,24 @@ EXPORT void SyntaxError( * \param format IN ??? * * \return FALSE in case of parsing error, TRUE on success + * In the error case, InputError had been called which may have closed the input file (paramFile) + * + * format chars are: + * 0 - read a number and discard + * X - no read, *pi = 0 + * Y - no read, *pf = 0L + * Z - no read, *pl = 0.0 + * L - *pi = number + * d - *pi = number + * w - *pf = read a width + * u - *pul = number + * l - *pl = number + * f - *pf = number + * z - *pf = 0.0 + * p - *pp = ( number, number ) a coOrd + * s - *ps = string + * q - *ps = quoted string + * c - *qp = position of next non-space char or NULL */ EXPORT BOOL_T GetArgs( @@ -266,7 +296,6 @@ EXPORT BOOL_T GetArgs( ... ) { char * cp, * cq; - int argNo; long * pl; unsigned long *pul; int * pi; @@ -276,25 +305,24 @@ EXPORT BOOL_T GetArgs( char ** qp; va_list ap; char *oldLocale = NULL; + char * sError = NULL; oldLocale = SaveLocale("C"); cp = line; va_start( ap, format ); - for (argNo=1;*format;argNo++,format++) { + for ( ; sError==NULL && *format; format++ ) { while (isspace((unsigned char)*cp)) cp++; if (!*cp && strchr( "XZYzc", *format ) == NULL ) { - RestoreLocale(oldLocale); - InputError( "Arg %d: EOL unexpected", TRUE, argNo ); - return FALSE; + sError = "EOL unexpected"; + break; } switch (*format) { case '0': (void)strtol( cp, &cq, 10 ); if (cp == cq) { - RestoreLocale(oldLocale); - InputError( "Arg %d: expected integer", TRUE, argNo ); - return FALSE; + sError = "%s: expected integer"; + break; } cp = cq; break; @@ -314,9 +342,8 @@ EXPORT BOOL_T GetArgs( pi = va_arg( ap, int * ); *pi = (int)strtol( cp, &cq, 10 ); if (cp == cq) { - RestoreLocale(oldLocale); - InputError( "Arg %d: expected integer", TRUE, argNo ); - return FALSE; + sError = "%s: expected integer"; + break; } cp = cq; break; @@ -324,9 +351,8 @@ EXPORT BOOL_T GetArgs( pi = va_arg( ap, int * ); *pi = (int)strtol( cp, &cq, 10 ); if (cp == cq) { - RestoreLocale(oldLocale); - InputError( "Arg %d: expected integer", TRUE, argNo ); - return FALSE; + sError = "%s: expected integer"; + break; } cp = cq; break; @@ -334,9 +360,8 @@ EXPORT BOOL_T GetArgs( pf = va_arg( ap, FLOAT_T * ); *pf = (FLOAT_T)strtol( cp, &cq, 10 ); if (cp == cq) { - RestoreLocale(oldLocale); - InputError( "Arg %d: expected integer", TRUE, argNo ); - return FALSE; + sError = "%s: expected integer"; + break; } if (*cq == '.') *pf = strtod( cp, &cq ); @@ -348,9 +373,8 @@ EXPORT BOOL_T GetArgs( pul = va_arg( ap, unsigned long * ); *pul = strtoul( cp, &cq, 10 ); if (cp == cq) { - RestoreLocale(oldLocale); - InputError( "Arg %d: expected integer", TRUE, argNo ); - return FALSE; + sError = "%s: expected integer"; + break; } cp = cq; break; @@ -358,9 +382,8 @@ EXPORT BOOL_T GetArgs( pl = va_arg( ap, long * ); *pl = strtol( cp, &cq, 10 ); if (cp == cq) { - RestoreLocale(oldLocale); - InputError( "Arg %d: expected integer", TRUE, argNo ); - return FALSE; + sError = "%s: expected integer"; + break; } cp = cq; break; @@ -368,43 +391,27 @@ EXPORT BOOL_T GetArgs( pf = va_arg( ap, FLOAT_T * ); *pf = strtod( cp, &cq ); if (cp == cq) { - RestoreLocale(oldLocale); - InputError( "Arg %d: expected float", TRUE, argNo ); - return FALSE; + sError = "%s: expected float"; + break; } cp = cq; break; case 'z': pf = va_arg( ap, FLOAT_T * ); -#ifdef LATER - if ( paramVersion >= 9 ) { - *pf = strtod( cp, &cq ); - if (cp == cq) { - RestoreLocale(oldLocale); - InputError( "Arg %d: expected float", TRUE, argNo ); - return FALSE; - } - cp = cq; - } else { - *pf = 0.0; - } -#endif *pf = 0.0; break; case 'p': pp = va_arg( ap, coOrd * ); p.x = strtod( cp, &cq ); if (cp == cq) { - RestoreLocale(oldLocale); - InputError( "Arg %d: expected float", TRUE, argNo ); - return FALSE; + sError = "%s: expected float"; + break; } cp = cq; p.y = strtod( cp, &cq ); if (cp == cq) { - RestoreLocale(oldLocale); - InputError( "Arg %d: expected float", TRUE, argNo ); - return FALSE; + sError = "%s: expected float"; + break; } cp = cq; *pp = p; @@ -446,7 +453,10 @@ EXPORT BOOL_T GetArgs( } else { message[0] = '\0'; } - *qp = (char*)MyStrdup(message); +#ifdef WINDOWS + ConvertUTF8ToSystem(message); +#endif + *qp = (char*)ConvertFromEscapedText(message); break; case 'c': qp = va_arg( ap, char * * ); @@ -457,14 +467,76 @@ EXPORT BOOL_T GetArgs( *qp = NULL; break; default: - AbortProg( "getArgs: bad format char" ); + AbortProg( "getArgs: bad format char: %c", *format ); } } va_end( ap ); RestoreLocale(oldLocale); + if ( sError ) { + InputError( sError, TRUE, cp ); + return FALSE; + } + return TRUE; +} + + + +wBool_t IsEND( char * sEnd ) +{ + char * cp; + wBool_t bAllowNakedENDs = paramVersion < 12; + for( cp = paramLine; *cp && (isspace( *cp ) || *cp == '\t'); cp++ ); + if ( strncmp( cp, sEnd, strlen(sEnd) ) == 0 ) + cp += strlen( sEnd ); + else if ( bAllowNakedENDs && strncmp( cp, "END", 3 ) == 0 ) + cp += 3; + else + return FALSE; + for ( ; *cp && isspace( *cp ); cp++ ); + if ( *cp != '\0' ) + return FALSE; return TRUE; } + +/** + * Read the text for a note/car. Lines are read from the input file + * until the END statement is found. + * + * \todo Handle premature end as an error + * + * \return pointer to string, has to be myfree'd by caller + */ + +char * +ReadMultilineText() +{ + char *string; + DynString noteText; + DynStringMalloc(¬eText, 0); + char *line; + + line = GetNextLine(); + + while ( !IsEND("END") ) { + DynStringCatCStr(¬eText, line); + DynStringCatCStr(¬eText, "\n"); + line = GetNextLine(); + } + string = MyStrdup(DynStringToCStr(¬eText)); + string[strlen(string) - 1] = '\0'; + +#ifdef WINDOWS + if (wIsUTF8(string)) { + ConvertUTF8ToSystem(string); + } +#endif // WINDOWS + + DynStringFree(¬eText); + return(string); +} + + EXPORT wBool_t ParseRoomSize( char * s, coOrd * roomSizeRet ) @@ -493,179 +565,37 @@ EXPORT wBool_t ParseRoomSize( return FALSE; } - +/** + * Parameter file parser definitions + * + * \param [IN] name command + * \param [IN] proc function for reading the parameter definition + * \param [IN] delete if not NULL function for freeing the definition + */ EXPORT void AddParam( char * name, - readParam_t proc ) + readParam_t proc) { DYNARR_APPEND( paramProc_t, paramProc_da, 10 ); paramProc(paramProc_da.cnt-1).name = name; paramProc(paramProc_da.cnt-1).proc = proc; } - -EXPORT BOOL_T ReadParams( - long key, - const char * dirName, - const char * fileName ) +EXPORT char * PutTitle( char * cp ) { - FILE * oldFile; - char *cp; - wIndex_t oldLineNum; - wIndex_t pc; - long oldCheckSum; - long checkSum=0; - BOOL_T checkSummed; - long paramVersion = -1; - char *oldLocale = NULL; + static char *title; + char * tp; + unsigned cnt = strlen(cp) * 2 + 3; // add 3 for quotes and terminating \0 - if (dirName) { - MakeFullpath(¶mFileName, dirName, fileName, NULL); + if (!title) { + title = MyMalloc(cnt); } else { - MakeFullpath(¶mFileName, fileName, NULL); - } - paramLineNum = 0; - curBarScale = -1; - curContents = strdup( fileName ); - curSubContents = curContents; - -LOG1( log_paramFile, ("ReadParam( %s )\n", fileName ) ) - - oldLocale = SaveLocale("C"); - - paramFile = fopen( paramFileName, "r" ); - if (paramFile == NULL) { - /* Reset the locale settings */ - RestoreLocale( oldLocale ); - - NoticeMessage( MSG_OPEN_FAIL, _("Continue"), NULL, _("Parameter"), paramFileName, strerror(errno) ); - - return FALSE; - } - paramCheckSum = key; - paramLineNum = 0; - checkSummed = FALSE; - while ( paramFile && ( fgets(paramLine, 256, paramFile) ) != NULL ) { - paramLineNum++; - Stripcr( paramLine ); - if (strncmp( paramLine, "CHECKSUM ", 9 ) == 0) { - checkSum = atol( paramLine+9 ); - checkSummed = TRUE; - goto nextLine; - } - ParamCheckSumLine( paramLine ); - if (paramLine[0] == '#') { - /* comment */ - } else if (paramLine[0] == 0) { - /* empty paramLine */ - } else if (strncmp( paramLine, "INCLUDE ", 8 ) == 0) { - cp = ¶mLine[8]; - while (*cp && isspace((unsigned char)*cp)) cp++; - if (!*cp) { - InputError( "INCLUDE - no file name", TRUE ); - - /* Close file and reset the locale settings */ - if (paramFile) fclose(paramFile); - RestoreLocale( oldLocale ); - - return FALSE; - } - oldFile = paramFile; - oldLineNum = paramLineNum; - oldCheckSum = paramCheckSum; - ReadParams( key, dirName, cp ); - paramFile = oldFile; - paramLineNum = oldLineNum; - paramCheckSum = oldCheckSum; - if (dirName) { - MakeFullpath(¶mFileName, dirName, fileName, NULL); - } else { - MakeFullpath(¶mFileName, fileName); - } - } else if (strncmp( paramLine, "CONTENTS ", 9) == 0 ) { - curContents = MyStrdup( paramLine+9 ); - curSubContents = curContents; - } else if (strncmp( paramLine, "SUBCONTENTS ", 12) == 0 ) { - curSubContents = MyStrdup( paramLine+12 ); - } else if (strncmp( paramLine, "PARAM ", 6) == 0 ) { - paramVersion = atol( paramLine+6 ); - } else { - for (pc = 0; pc < paramProc_da.cnt; pc++ ) { - if (strncmp( paramLine, paramProc(pc).name, - strlen(paramProc(pc).name)) == 0 ) { - paramProc(pc).proc( paramLine ); - goto nextLine; - } - } - InputError( "Unknown param line", TRUE ); - } - nextLine:; + title = MyRealloc(title, cnt); } - if ( key ) { - if ( !checkSummed || checkSum != paramCheckSum ) { - /* Close file and reset the locale settings */ - if (paramFile) fclose(paramFile); - RestoreLocale( oldLocale ); - - NoticeMessage( MSG_PROG_CORRUPTED, _("Ok"), NULL, paramFileName ); - - return FALSE; - } - } - if (paramFile)fclose( paramFile ); - free(paramFileName); - paramFileName = NULL; - RestoreLocale( oldLocale ); - - return TRUE; -} + tp = title; -static void ReadCustom( void ) -{ - FILE * f; - MakeFullpath(&customPath, workingDir, sCustomF, NULL); - customPathBak = MyStrdup( customPath ); - customPathBak[ strlen(customPathBak)-1 ] = '1'; - f = fopen( customPath, "r" ); - if ( f != NULL ) { - fclose( f ); - curParamFileIndex = PARAM_CUSTOM; - ReadParams( 0, workingDir, sCustomF ); - } -} - - -/* - * Open the file and then set the locale to "C". Old locale will be copied to - * oldLocale. After the required file I/O is done, the caller must call - * CloseCustom() with the same locale value that was returned in oldLocale by - * this function. - */ -EXPORT FILE * OpenCustom( char *mode ) -{ - FILE * ret = NULL; - - if (inPlayback) - return NULL; - if ( *mode == 'w' ) - rename( customPath, customPathBak ); - if (customPath) { - ret = fopen( customPath, mode ); - if (ret == NULL) { - NoticeMessage( MSG_OPEN_FAIL, _("Continue"), NULL, _("Custom"), customPath, strerror(errno) ); - } - } - - return ret; -} - - -EXPORT char * PutTitle( char * cp ) -{ - static char title[STR_SIZE]; - char * tp = title; - while (*cp && (tp-title)<=(sizeof title)-3) { + while (*cp ) { if (*cp == '\"') { *tp++ = '\"'; *tp++ = '\"'; @@ -677,6 +607,16 @@ EXPORT char * PutTitle( char * cp ) if ( *cp ) NoticeMessage( _("putTitle: title too long: %s"), _("Ok"), NULL, title ); *tp = '\0'; + +#ifdef WINDOWS + if(RequiresConvToUTF8(title)) { + char *out = MyMalloc(cnt); + wSystemToUTF8(title, out, cnt); + strcpy(title, out); + MyFree(out); + } +#endif // WINDOWS + return title; } @@ -694,20 +634,25 @@ void SetWindowTitle( void ) return; filename = GetLayoutFilename(); - sprintf( message, "%s%s - %s(%s)", + sprintf( message, "%s%s%s - %s(%s)", (filename && filename[0])?filename: _("Unnamed Trackplan"), - changed>0?"*":"", sProdName, sVersion ); + bReadOnly?_(" (R/O)"):"", + changed>0?"*":"", + sProdName, sVersion ); wWinSetTitle( mainW, message ); } - + + + /***************************************************************************** * * LOAD / SAVE TRACKS * */ -static struct wFilSel_t * loadFile_fs; -static struct wFilSel_t * saveFile_fs; +static struct wFilSel_t * loadFile_fs = NULL; +static struct wFilSel_t * saveFile_fs = NULL; +static struct wFilSel_t * examplesFile_fs = NULL; static wWin_p checkPointingW; static paramData_t checkPointingPLs[] = { @@ -716,6 +661,7 @@ static paramGroup_t checkPointingPG = { "checkpoint", 0, checkPointingPLs, sizeo static char * checkPtFileName1; static char * checkPtFileName2; +static char * checkPtFileNameBackup; /** Read the layout design. * @@ -760,8 +706,12 @@ static BOOL_T ReadTrackFile( InfoMessage("0"); count = 0; + int skipLines = 0; + BOOL_T skip = FALSE; while ( paramFile && ( fgets(paramLine, sizeof paramLine, paramFile) ) != NULL ) { count++; + BOOL_T old_skip = skip; + skip = FALSE; if (count%10 == 0) { InfoMessage( "%d", count ); wFlush(); @@ -781,8 +731,8 @@ static BOOL_T ReadTrackFile( } if (ReadTrack( paramLine )) { - - } else if (strncmp( paramLine, "END", 3 ) == 0) { + continue; + } else if (IsEND( END_TRK_FILE ) ) { break; } else if (strncmp( paramLine, "VERSION ", 8 ) == 0) { paramVersion = strtol( paramLine+8, &cp, 10 ); @@ -804,8 +754,14 @@ static BOOL_T ReadTrackFile( if( !(ret = InputError( "unknown command", TRUE ))) break; } else if (strncmp( paramLine, "TITLE1 ", 7 ) == 0) { +#ifdef WINDOWS + ConvertUTF8ToSystem(paramLine + 7); +#endif // WINDOWS SetLayoutTitle(paramLine + 7); } else if (strncmp( paramLine, "TITLE2 ", 7 ) == 0) { +#ifdef WINDOWS + ConvertUTF8ToSystem(paramLine + 7); +#endif // WINDOWS SetLayoutSubtitle(paramLine + 7); } else if (strncmp( paramLine, "ROOMSIZE", 8 ) == 0) { if ( ParseRoomSize( paramLine+8, &roomSize ) ) { @@ -829,39 +785,44 @@ static BOOL_T ReadTrackFile( } else if (strncmp( paramLine, "LAYERS ", 7 ) == 0) { ReadLayers( paramLine+7 ); } else { - if( !(ret = InputError( "unknown command", TRUE ))) - break; + if (!old_skip) { + if (InputError(_("Unknown layout file object - skip until next good object?"), TRUE)) { //OK to carry on + /* SKIP until next main line we recognize */ + skip = TRUE; + skipLines++; + continue; + } else { + break; //Close File + } + } else skip = TRUE; + skipLines++; } } - if (paramFile) + if (paramFile) { fclose(paramFile); + paramFile = NULL; + } if( ret ) { if (!noSetCurDir) SetCurrentPath( LAYOUTPATHKEY, fileName ); - - if (full) { -// SetCurrentPath(LAYOUTPATHKEY, pathName); - SetLayoutFullPath(pathName); - //strcpy(curPathName, pathName); - //curFileName = &curPathName[fileName-pathName]; - SetWindowTitle(); - } } + if (skipLines>0) + NoticeMessage( MSG_LAYOUT_LINES_SKIPPED, _("Ok"), NULL, paramFileName, skipLines); + RestoreLocale( oldLocale ); paramFile = NULL; free(paramFileName); - paramFileName = NULL; + paramFileName = NULL; InfoMessage( "%d", count ); return ret; } - -EXPORT int LoadTracks( +int LoadTracks( int cnt, char **fileName, void * data) @@ -869,18 +830,23 @@ EXPORT int LoadTracks( #ifdef TIME_READTRACKFILE long time0, time1; #endif - char *nameOfFile; + char *nameOfFile = NULL; + + char *extOfFile; assert( fileName != NULL ); - assert( cnt == 1 ); + assert( cnt == 1 ); - SetCurrentPath(LAYOUTPATHKEY, fileName[0]); + if ( ! bExample ) + SetCurrentPath(LAYOUTPATHKEY, fileName[0]); + bReadOnly = bExample; paramVersion = -1; - wSetCursor( wCursorWait ); + wSetCursor( mainD.d, wCursorWait ); Reset(); ClearTracks(); ResetLayers(); checkPtMark = changed = 0; + LayoutBackGroundInit(TRUE); //Keep values of background -> will be overriden my archive UndoSuspend(); useCurrentLayer = FALSE; #ifdef TIME_READTRACKFILE @@ -888,8 +854,119 @@ EXPORT int LoadTracks( #endif nameOfFile = FindFilename( fileName[ 0 ] ); - if (ReadTrackFile( fileName[ 0 ], nameOfFile, TRUE, FALSE, TRUE )) { - wMenuListAdd( fileList_ml, 0, nameOfFile, MyStrdup(fileName[0]) ); + /* + * Support zipped filetype + */ + extOfFile = FindFileExtension( nameOfFile); + + BOOL_T zipped = FALSE; + BOOL_T loadXTC = TRUE; + char * full_path = strdup(fileName[0]); + + if (extOfFile && (strcmp(extOfFile, ZIPFILETYPEEXTENSION )==0)) { + + char * zip_input = GetZipDirectoryName(ARCHIVE_READ); + + //If zipped unpack file into temporary input dir (cleared and re-created) + + DeleteDirectory(zip_input); + SafeCreateDir(zip_input); + + if (UnpackArchiveFor(fileName[0], nameOfFile, zip_input, FALSE)) { + + char * manifest_file; + + MakeFullpath(&manifest_file, zip_input, "manifest.json", NULL); + + char * manifest = 0; + long length; + + FILE * f = fopen (manifest_file, "rb"); + + if (f) + { + fseek(f, 0, SEEK_END); + length = ftell(f); + fseek(f, 0, SEEK_SET); + manifest = malloc(length + 1); + if (manifest) { + size_t siz = fread(manifest, 1, length, f); + manifest[length] = '\0'; + } + fclose(f); + } else + { + NoticeMessage(MSG_MANIFEST_OPEN_FAIL, _("Continue"), NULL, manifest_file); + } + free(manifest_file); + + char * arch_file = NULL; + + //Set filename to point to included .xtc file + //Use the name inside manifest (this helps if a user renames the zip) + if (manifest) + { + arch_file = ParseManifest(manifest, zip_input); + free(manifest); + } + + free(full_path); + full_path = NULL; + // If no manifest value use same name as the archive + if (arch_file && arch_file[0]) + { + MakeFullpath(&full_path, zip_input, arch_file, NULL); + } else + { + MakeFullpath(&full_path, zip_input, nameOfFile, NULL); + } + + nameOfFile = FindFilename(full_path); + extOfFile = FindFileExtension(full_path); + if (strcmp(extOfFile, ZIPFILETYPEEXTENSION )==0) + { + for (int i=0; i<4; i++) { + extOfFile[i] = extOfFile[i+1]; + } + } + LOG(log_zip, 1, ("Zip-File %s \n", full_path)) + #if DEBUG + printf("File Path: %s \n", full_path); + #endif + } else { + loadXTC = FALSE; // when unzipping fails, don't attempt loading the trackplan + } + zipped = TRUE; + + free(zip_input); + + + } + + if ( bExample ) + bReadOnly = TRUE; + else if ( access( fileName[0], W_OK ) == -1 ) + bReadOnly = TRUE; + else + bReadOnly = FALSE; + + char *copyOfFileName = MyStrdup(fileName[0]); + + if (loadXTC && ReadTrackFile( full_path, FindFilename( fileName[0]), TRUE, TRUE, TRUE )) { + + nameOfFile = NULL; + extOfFile = NULL; + SetCurrentPath( LAYOUTPATHKEY, copyOfFileName ); + SetLayoutFullPath(copyOfFileName); + SetWindowTitle(); + + if ( ! bExample && (nameOfFile != NULL) ) { + char * copyFile = strdup(fileName[0]); + char * listName = FindFilename(strdup(fileName[0])); //Make sure the list name is new + wMenuListAdd( fileList_ml, 0, listName, copyFile ); + } + + ResolveIndex(); #ifdef TIME_READTRACKFILE time1 = wGetTimer(); @@ -902,9 +979,14 @@ EXPORT int LoadTracks( LoadLayerLists(); LayerSetCounts(); } + + MyFree(copyOfFileName); + free(full_path); + full_path = NULL; + UndoResume(); Reset(); - wSetCursor( wCursorNormal ); + wSetCursor( mainD.d, defaultCursor ); return TRUE; } @@ -913,7 +995,7 @@ EXPORT int LoadTracks( * path. * \param index IN ignored * \param label IN ignored - * \param data IN path and filename + * \param data IN path and filename */ EXPORT void DoFileList( @@ -922,7 +1004,7 @@ EXPORT void DoFileList( void * data ) { char *pathName = (char*)data; - + bExample = FALSE; LoadTracks( 1, &pathName, NULL ); } @@ -945,7 +1027,7 @@ static BOOL_T DoSaveTracks( return FALSE; } - wSetCursor( wCursorWait ); + wSetCursor( mainD.d, wCursorWait ); time(&clock); rc &= fprintf(f,"#%s Version: %s, Date: %s\n", sProdName, sVersion, ctime(&clock) )>0; rc &= fprintf(f, "VERSION %d %s\n", iParamVersion, PARAMVERSIONVERSION )>0; @@ -958,34 +1040,156 @@ static BOOL_T DoSaveTracks( rc &= fprintf(f, "SCALE %s\n", curScaleName )>0; rc &= WriteLayers( f ); rc &= WriteMainNote( f ); - rc &= WriteTracks( f ); - rc &= fprintf(f, "END\n")>0; + rc &= WriteTracks( f, TRUE ); + rc &= fprintf(f, "%s\n", END_TRK_FILE)>0; if ( !rc ) NoticeMessage( MSG_WRITE_FAILURE, _("Ok"), NULL, strerror(errno), fileName ); fclose(f); + bReadOnly = FALSE; RestoreLocale( oldLocale ); checkPtMark = changed; - wSetCursor( wCursorNormal ); + wSetCursor( mainD.d, defaultCursor ); return rc; } +/************************************************ + * Copy Dependency - copy file into another directory + * + * \param IN name + * \param IN target_dir + * + * \returns TRUE for success + * + */ +static BOOL_T CopyDependency(char * name, char * target_dir) +{ + char * backname = FindFilename(name); + BOOL_T copied = TRUE; + FILE * source = fopen(name, "rb"); + + if (source != NULL) { + char * target_file; + MakeFullpath(&target_file, target_dir, backname, NULL); + FILE * target = fopen(target_file, "wb"); + + if (target != NULL) { + char *buffer = MyMalloc(COPYBLOCKSIZE); + while (!feof(source)) { + size_t bytes = fread(buffer, 1, sizeof(buffer), source); + if (bytes) { + fwrite(buffer, 1, bytes, target); + } + } + MyFree(buffer); + LOG(log_zip, 1, ("Zip-Include %s into %s \n", name, target_file)) +#if DEBUG + printf("xtrkcad: Included file %s into %s \n", + name, target_file); +#endif + fclose(target); + } else { + NoticeMessage(MSG_COPY_FAIL, _("Continue"), NULL, name, target_file); + copied = FALSE; + } + free(target_file); + fclose(source); + } else { + NoticeMessage(MSG_COPY_OPEN_FAIL, _("Continue"), NULL, name); + copied = FALSE; + } + return copied; +} + static doSaveCallBack_p doAfterSave; + + static int SaveTracks( int cnt, char **fileName, void * data ) { - char *nameOfFile; assert( fileName != NULL ); assert( cnt == 1 ); + char *nameOfFile = FindFilename(fileName[0]); + SetCurrentPath(LAYOUTPATHKEY, fileName[0]); - DoSaveTracks( fileName[ 0 ] ); + + //Support Archive zipped files + + char * extOfFile = FindFileExtension( fileName[0]); + + + if (extOfFile && (strcmp(extOfFile,ZIPFILETYPEEXTENSION)==0)) { + + char * ArchiveName; + + //Set filename to point to be the same as the included .xtc file. + //This is also in the manifest - in case a user renames the archive file. + + char * zip_output = GetZipDirectoryName(ARCHIVE_WRITE); + + DeleteDirectory(zip_output); + SafeCreateDir(zip_output); + + MakeFullpath(&ArchiveName, zip_output, nameOfFile, NULL); + + nameOfFile = FindFilename(ArchiveName); + extOfFile = FindFileExtension(ArchiveName); + + if (extOfFile && strcmp(extOfFile, ZIPFILETYPEEXTENSION)==0) { + // Get rid of the 'e' + extOfFile[3] = '\0'; + } + + char * DependencyDir; + + //The included files are placed (for now) into an includes directory - TODO an array of includes with directories by type + MakeFullpath(&DependencyDir, zip_output, "includes", NULL); + + SafeCreateDir(DependencyDir); + + char * background = GetLayoutBackGroundFullPath(); + + if (background && background[0]) + CopyDependency(background,DependencyDir); + + //The details are stored into the manifest - TODO use arrays for files, locations + char *oldLocale = SaveLocale("C"); + char* json_Manifest = CreateManifest(nameOfFile, background, "includes"); + char * manifest_file; + + MakeFullpath(&manifest_file, zip_output, "manifest.json", NULL); + + FILE *fp = fopen(manifest_file, "wb"); + if (fp != NULL) + { + fputs(json_Manifest, fp); + fclose(fp); + } else { + NoticeMessage( MSG_MANIFEST_FAIL, _("Continue"), NULL, manifest_file ); + } + RestoreLocale(oldLocale); + + free(manifest_file); + free(json_Manifest); + + DoSaveTracks( ArchiveName ); + + if (CreateArchive( zip_output, fileName[0]) != TRUE) { + NoticeMessage( MSG_ARCHIVE_FAIL, _("Continue"), NULL, fileName[0], zip_output ); + } + free(zip_output); + free(ArchiveName); + + } else + + DoSaveTracks( fileName[ 0 ] ); nameOfFile = FindFilename( fileName[ 0 ] ); wMenuListAdd( fileList_ml, 0, nameOfFile, MyStrdup(fileName[ 0 ]) ); @@ -1003,16 +1207,18 @@ static int SaveTracks( EXPORT void DoSave( doSaveCallBack_p after ) { doAfterSave = after; - if (*(GetLayoutFilename()) == '\0') { + if ( bReadOnly || *(GetLayoutFilename()) == '\0') { if (saveFile_fs == NULL) saveFile_fs = wFilSelCreate( mainW, FS_SAVE, 0, _("Save Tracks"), sSourceFilePattern, SaveTracks, NULL ); wFilSelect( saveFile_fs, GetCurrentPath(LAYOUTPATHKEY)); + changed = checkPtMark = 1; } else { - char *temp = GetLayoutFullPath(); + char *temp = GetLayoutFullPath(); SaveTracks( 1, &temp, NULL ); } SetWindowTitle(); + SaveState(); } EXPORT void DoSaveAs( doSaveCallBack_p after ) @@ -1020,46 +1226,93 @@ EXPORT void DoSaveAs( doSaveCallBack_p after ) doAfterSave = after; if (saveFile_fs == NULL) saveFile_fs = wFilSelCreate( mainW, FS_SAVE, 0, _("Save Tracks As"), - sSourceFilePattern, SaveTracks, NULL ); + sSaveFilePattern, SaveTracks, NULL ); wFilSelect( saveFile_fs, GetCurrentPath(LAYOUTPATHKEY)); + changed = checkPtMark = 1; SetWindowTitle(); + SaveState(); } EXPORT void DoLoad( void ) { - loadFile_fs = wFilSelCreate( mainW, FS_LOAD, 0, _("Open Tracks"), - sSourceFilePattern, LoadTracks, NULL ); + if (loadFile_fs == NULL) + loadFile_fs = wFilSelCreate( mainW, FS_LOAD, 0, _("Open Tracks"), + sSourceFilePattern, LoadTracks, NULL ); + bExample = FALSE; wFilSelect( loadFile_fs, GetCurrentPath(LAYOUTPATHKEY)); + paste_offset = zero; + cursor_offset = zero; + SaveState(); } +EXPORT void DoExamples( void ) +{ + if (examplesFile_fs == NULL) { + static wBool_t bExample = TRUE; + examplesFile_fs = wFilSelCreate( mainW, FS_LOAD, 0, _("Example Tracks"), + sSourceFilePattern, LoadTracks, &bExample ); + } + bExample = TRUE; + sprintf( message, "%s" FILE_SEP_CHAR "examples" FILE_SEP_CHAR, libDir ); + wFilSelect( examplesFile_fs, message ); + SaveState(); +} + +static wIndex_t generations_count = 0; +wIndex_t max_generations_count = 10; +static char sCheckPointBF[STR_LONG_SIZE]; + + EXPORT void DoCheckPoint( void ) { int rc; + if (!checkPtFileNameBackup || (changed <= checkPtInterval+1)) { + sprintf(sCheckPointBF,"%s00.bkp",GetLayoutFilename()); + MakeFullpath(&checkPtFileNameBackup, workingDir, sCheckPointBF, NULL); + } + if (checkPointingW == NULL) { ParamRegister( &checkPointingPG ); checkPointingW = ParamCreateDialog( &checkPointingPG, MakeWindowTitle(_("Check Pointing")), NULL, NULL, NULL, FALSE, NULL, F_TOP|F_CENTER, NULL ); } rename( checkPtFileName1, checkPtFileName2 ); - wShow( checkPointingW ); + //wShow( checkPointingW ); rc = DoSaveTracks( checkPtFileName1 ); /* could the check point file be written ok? */ if( rc ) { - /* yes, delete the backup copy of the checkpoint file */ - remove( checkPtFileName2 ); + /* yes, archive/delete the backup copy of the checkpoint file */ + if (checkPtFileNameBackup) { + char * spot = strrchr(checkPtFileNameBackup,'.'); + if (spot && spot>checkPtFileNameBackup+3) { + spot[-2]=generations_count/10+'0'; + spot[-1]=generations_count%10+'0'; + } + generations_count++; + if (((autosaveChkPoints == 0) && (generations_count > 5)) || + ((autosaveChkPoints > 0) && (generations_count > autosaveChkPoints)) ) { + generations_count = 0; + } + remove( checkPtFileNameBackup); + rename( checkPtFileName2, checkPtFileNameBackup ); + } else { + remove(checkPtFileName2); + } } else { /* no, rename the backup copy back to the checkpoint file name */ rename( checkPtFileName2, checkPtFileName1 ); } - wHide( checkPointingW ); + + //wHide( checkPointingW ); + wShow( mainW ); } /** - * Remove all temporary files before exiting.When the program terminates - * normally through the exit choice, files that are created temporarily are removed: - * xtrkcad.ckp + * Remove all temporary files before exiting. When the program terminates + * normally through the exit choice, files and directories that were created + * temporarily are removed: xtrkcad.ckp * * \param none * \return none @@ -1068,12 +1321,27 @@ EXPORT void DoCheckPoint( void ) EXPORT void CleanupFiles( void ) { - if( checkPtFileName1 ) + char *tempDir; + + if( checkPtFileName1 ) { + if (checkPtFileNameBackup) { + remove( checkPtFileNameBackup ); + rename( checkPtFileName1, checkPtFileNameBackup ); + } remove( checkPtFileName1 ); + } + + for (int i = ARCHIVE_READ; i <= ARCHIVE_WRITE; ++i) { + tempDir = GetZipDirectoryName(i); + if (tempDir) { + DeleteDirectory(tempDir); + free(tempDir); + } + } } /** - * Check for existance of checkpoint file. Existance of a checkpoint file means that XTrkCAD was not properly + * Check for existence of checkpoint file. Existence of a checkpoint file means that XTrkCAD was not properly * terminated. * * \param none @@ -1098,37 +1366,52 @@ EXPORT int ExistsCheckpoint( void ) /** * Load checkpoint file * + * \param if TRUE reuse old filename + * \param filename returned * \return TRUE if exists, FALSE otherwise * */ -EXPORT int LoadCheckpoint( void ) +EXPORT int LoadCheckpoint( BOOL_T sameName ) { char *search; paramVersion = -1; - wSetCursor( wCursorWait ); + wSetCursor( mainD.d, wCursorWait ); MakeFullpath(&search, workingDir, sCheckPointF, NULL); UndoSuspend(); if (ReadTrackFile( search, search + strlen(search) - strlen( sCheckPointF ), TRUE, TRUE, TRUE )) { ResolveIndex(); + LayoutBackGroundInit(FALSE); //Get Prior BackGround + LayoutBackGroundSave(); //Save Background Values + + if (sameName) { + long iExample; + char * initialFile = (char*)wPrefGetString("misc", "lastlayout"); + wPrefGetInteger("misc", "lastlayoutexample", &iExample, 0); + bExample = (iExample == 1); + if (initialFile && strlen(initialFile)) { + SetCurrentPath( LAYOUTPATHKEY, initialFile ); + SetLayoutFullPath(initialFile); + } + } else SetLayoutFullPath(""); RecomputeElevations(); AttachTrains(); DoChangeNotification( CHANGE_ALL ); DoUpdateTitles(); - } + } else SetLayoutFullPath(""); Reset(); UndoResume(); - wSetCursor( wCursorNormal ); + wSetCursor( mainD.d, defaultCursor ); + - SetLayoutFullPath(""); SetWindowTitle(); - changed = TRUE; + checkPtMark = changed = 1; free( search ); return TRUE; } @@ -1142,6 +1425,15 @@ EXPORT int LoadCheckpoint( void ) static struct wFilSel_t * exportFile_fs; static struct wFilSel_t * importFile_fs; +static int importAsModule; + + + +/******************************************************************************* + * + * Import Layout Dialog + * + */ static int ImportTracks( int cnt, @@ -1156,27 +1448,40 @@ static int ImportTracks( nameOfFile = FindFilename(fileName[ 0 ]); paramVersion = -1; - wSetCursor( wCursorWait ); + wSetCursor( mainD.d, wCursorWait ); Reset(); SetAllTrackSelect( FALSE ); + int saveLayer = curLayer; + int layer; + if (importAsModule) { + layer = FindUnusedLayer(0); + if (layer==-1) return FALSE; + char LayerName[80]; + LayerName[0] = '\0'; + sprintf(LayerName,_("Module - %s"),nameOfFile); + if (layer>=0) SetCurrLayer(layer, NULL, 0, NULL, NULL); + SetLayerName(layer,LayerName); + } ImportStart(); UndoStart( _("Import Tracks"), "importTracks" ); useCurrentLayer = TRUE; ReadTrackFile( fileName[ 0 ], nameOfFile, FALSE, FALSE, TRUE ); - ImportEnd(); + ImportEnd(zero, TRUE, FALSE); + if (importAsModule) SetLayerModule(layer,TRUE); + useCurrentLayer = FALSE; + SetCurrLayer(saveLayer, NULL, 0, NULL, NULL); /*DoRedraw();*/ EnableCommands(); - wSetCursor( wCursorNormal ); + wSetCursor( mainD.d, defaultCursor ); paramVersion = paramVersionOld; - importMove = TRUE; DoCommandB( (void*)(intptr_t)selectCmdInx ); SelectRecount(); return TRUE; } - -EXPORT void DoImport( void ) +EXPORT void DoImport( void * type ) { + importAsModule = (int)(long)type; if (importFile_fs == NULL) importFile_fs = wFilSelCreate( mainW, FS_LOAD, 0, _("Import Tracks"), sImportFilePattern, ImportTracks, NULL ); @@ -1215,18 +1520,19 @@ static int DoExportTracks( oldLocale = SaveLocale("C"); - wSetCursor( wCursorWait ); + wSetCursor( mainD.d, wCursorWait ); time(&clock); fprintf(f,"#%s Version: %s, Date: %s\n", sProdName, sVersion, ctime(&clock) ); fprintf(f, "VERSION %d %s\n", iParamVersion, PARAMVERSIONVERSION ); - ExportTracks( f ); - fprintf(f, "END\n"); + coOrd offset; + ExportTracks( f , &offset); + fprintf(f, "%s\n", END_TRK_FILE); fclose(f); RestoreLocale( oldLocale ); Reset(); - wSetCursor( wCursorNormal ); + wSetCursor( mainD.d, defaultCursor ); UpdateAllElevations(); return TRUE; } @@ -1246,7 +1552,6 @@ EXPORT void DoExport( void ) } - EXPORT BOOL_T EditCopy( void ) { FILE * f; @@ -1268,10 +1573,11 @@ EXPORT BOOL_T EditCopy( void ) time(&clock); fprintf(f,"#%s Version: %s, Date: %s\n", sProdName, sVersion, ctime(&clock) ); fprintf(f, "VERSION %d %s\n", iParamVersion, PARAMVERSIONVERSION ); - ExportTracks(f); - fprintf(f, "END\n"); + ExportTracks(f, &paste_offset); + fprintf(f, "%s\n", END_TRK_FILE ); RestoreLocale(oldLocale); fclose(f); + return TRUE; } @@ -1284,6 +1590,7 @@ EXPORT BOOL_T EditCut( void ) return TRUE; } + /** * Paste clipboard content. XTrackCAD uses a disk file as clipboard replacement. This file is read and the * content is inserted. @@ -1291,16 +1598,24 @@ EXPORT BOOL_T EditCut( void ) * \return TRUE if success, FALSE on error (file not found) */ -EXPORT BOOL_T EditPaste( void ) +BOOL_T EditPastePlace( wBool_t inPlace ) { + BOOL_T rc = TRUE; char *oldLocale = NULL; oldLocale = SaveLocale("C"); - wSetCursor( wCursorWait ); + wSetCursor( mainD.d, wCursorWait ); Reset(); SetAllTrackSelect( FALSE ); + + double offset = 20*mainD.scale/mainD.dpi; + + paste_offset.x += offset; + paste_offset.y += offset; + + ImportStart(); UndoStart( _("Paste"), "paste" ); useCurrentLayer = TRUE; @@ -1308,18 +1623,33 @@ EXPORT BOOL_T EditPaste( void ) NoticeMessage( MSG_CANT_PASTE, _("Continue"), NULL ); rc = FALSE; } - ImportEnd(); + if (inPlace) + ImportEnd(paste_offset, FALSE, TRUE); + else + ImportEnd(zero, FALSE, FALSE); + useCurrentLayer = FALSE; /*DoRedraw();*/ EnableCommands(); - wSetCursor( wCursorNormal ); - importMove = TRUE; + wSetCursor( mainD.d, defaultCursor ); DoCommandB( (void*)(intptr_t)selectCmdInx ); SelectRecount(); UpdateAllElevations(); RestoreLocale(oldLocale); + return rc; } + +EXPORT BOOL_T EditPaste( void) { + return EditPastePlace(FALSE); +} +EXPORT BOOL_T EditClone( void ) { + BOOL_T rc = TRUE; + if (!EditCopy()) return FALSE; + if (!EditPastePlace(TRUE)) return FALSE; + return rc; +} + /***************************************************************************** * * INITIALIZATION @@ -1333,23 +1663,8 @@ EXPORT void FileInit( void ) } if ( (workingDir = wGetAppWorkDir()) == NULL ) AbortProg( "wGetAppWorkDir()" ); -} - -EXPORT BOOL_T ParamFileInit( void ) -{ - curParamFileIndex = PARAM_DEMO; - log_paramFile = LogFindIndex( "paramFile" ); - if ( ReadParams( lParamKey, libDir, sParamQF ) == FALSE ) - return FALSE; - - curParamFileIndex = PARAM_CUSTOM; - if (lParamKey == 0) { - ReadParamFiles(); - ReadCustom(); - } SetLayoutFullPath(""); - MakeFullpath(&clipBoardN, workingDir, sClipboardF, NULL); - return TRUE; + MakeFullpath(&clipBoardN, workingDir, sClipboardF, NULL); } -- cgit v1.2.3