1 /* The code in this file writes a sample Igor Pro packed experiment file.
2
3 See Igor Pro Tech Note PTN#003 for details.
4 */
5
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <stddef.h> // For offsetof macro.
10
11 #include "PackedFile.h"
12 #include "Variables.h"
13 #include "IgorBin.h"
14 #include "CrossPlatformFileIO.h"
15 #include "IgorSupport.h"
16
17 #include "PackedFileDemo.h"
18
19 // Constants
20 #define NOMEM 1 // Error code for out of memory.
21 #define DEMO_WAVE_LENGTH 10 // Number of points in the demo wave.
22
23 static void
PrintResult(const char * message,int error)24 PrintResult(const char* message, int error)
25 {
26 char buffer[256];
27
28 if (error)
29 sprintf(buffer, "Error %d: %s", error, message);
30 else
31 strcpy(buffer, message);
32 printf("%s\n", buffer);
33 }
34
35 static int
WriteDemoVariablesRecord(CP_FILE_REF fr)36 WriteDemoVariablesRecord(CP_FILE_REF fr)
37 {
38 unsigned long recordStartPos;
39 char temp[256];
40 int err;
41
42 if (err = CPGetFilePosition(fr, &recordStartPos)) // Remember where record starts in the file.
43 return err;
44
45 // Write the generic packed file record header. numDataBytes field will be updated later.
46 if (err = WriteRecordHeader(fr, kVariablesRecord, 0, 0))
47 return err;
48
49 // Write the specific header for variables data.
50 if (err = WriteVariablesHeader(fr, 0, 1, 1, 0, 0)) // There will be one numeric and one string variable.
51 return err;
52
53 // Write the numeric variable.
54 if (err = WriteNumericVar(fr, "userNumVar", 0, 1234.0, 0.0))
55 return err;
56
57 // Write the string variable.
58 strcpy(temp, "This is a string variable.");
59 if (err = WriteStringVar(fr, "userStrVar", temp, strlen(temp)))
60 return err;
61
62 // Update the numDataBytes field to record the actual length of the data.
63 if (err = SetRecordHeaderNumDataBytesField(fr, recordStartPos))
64 return err;
65
66 return 0;
67 }
68
69 static void
SetDemoWaveDataContents(float * fp,long numPoints)70 SetDemoWaveDataContents(float* fp, long numPoints)
71 {
72 float val;
73
74 val = 0.0;
75 while(numPoints > 0) {
76 *fp++ = val;
77 val += 1.0;
78 numPoints -= 1;
79 }
80 }
81
82 static int
WriteDemoWave1DNumericWaveRecord(CP_FILE_REF fr)83 WriteDemoWave1DNumericWaveRecord(CP_FILE_REF fr)
84 {
85 WaveHeader2 wh;
86 float* data;
87 unsigned long recordStartPos;
88 unsigned long creationDate;
89 long waveMainDataSize, noteSize;
90 char note[256];
91 int err;
92
93 if (err = CPGetFilePosition(fr, &recordStartPos)) // Remember where record starts in the file.
94 return err;
95
96 // Write the generic packed file record header. numDataBytes field will be updated later.
97 if (err = WriteRecordHeader(fr, kWaveRecord, 0, 0))
98 return err;
99
100 // It is OK to pass 0 for creationDate if you don't care about it.
101 #ifdef WIN32
102 creationDate = 0; // GetDateTime can be simulated on Windows but it is fairly complicated.
103 #else
104 GetDateTime(&creationDate); // Seconds since midnight, January 1, 1904.
105 #endif
106
107 // Create the demo data.
108 waveMainDataSize = DEMO_WAVE_LENGTH * sizeof(float); // Size of just the numeric data.
109 data = malloc(waveMainDataSize);
110 if (data == NULL)
111 return NOMEM;
112 SetDemoWaveDataContents(data, DEMO_WAVE_LENGTH);
113
114 // This sets structure to be valid for a 1D numeric wave.
115 InitWaveHeader2(&wh, "wave0", creationDate, DEMO_WAVE_LENGTH, NT_FP32);
116
117 // Set X scaling. x = hsA*p + hsB.
118 wh.hsA = 0.2;
119 wh.hsB = 0.0;
120
121 /* For the checksum calculated by WriteVersion2NumericWave, the wData field of the
122 WaveHeader2 structure must contain the same data as the first 16 bytes of the main
123 wave data. The wData field was cleared by InitWaveHeader2.
124 */
125 {
126 int tmp = 16;
127 if (waveMainDataSize < tmp)
128 tmp = waveMainDataSize;
129 memcpy(&wh.wData, data, tmp);
130 }
131
132 // We need to know the size of the wave note.
133 strcpy(note, "This is wave0.");
134 noteSize = strlen(note);
135
136 // Write the wave.
137 err = WriteVersion2NumericWave(fr, &wh, data, note, strlen(note));
138 free(data);
139 if (err)
140 return err;
141
142 // Update the numDataBytes field to record the actual length of the data.
143 if (err = SetRecordHeaderNumDataBytesField(fr, recordStartPos))
144 return err;
145
146 return 0;
147 }
148
149 static int
WriteDemoRecreationProcedures(CP_FILE_REF fr)150 WriteDemoRecreationProcedures(CP_FILE_REF fr)
151 {
152 char text[1024];
153
154 // Generate text to call the Table0() macro defined below.
155 strcpy(text, "Table0()"CR_STR);
156 strcat(text, CR_STR);
157
158 // Generate text for a table recreation macro to display wave0.
159 strcat(text, "Window Table0() : Table"CR_STR);
160 strcat(text, "\tPauseUpdate; Silent 1 | building window..."CR_STR);
161 strcat(text, "\tEdit wave0"CR_STR);
162 strcat(text, "End"CR_STR);
163
164 return WritePlainTextRecord(fr, kRecreationRecord, text, strlen(text));
165 }
166
167 static int
WriteDemoProcedureWindowProcedures(CP_FILE_REF fr)168 WriteDemoProcedureWindowProcedures(CP_FILE_REF fr)
169 {
170 char text[1024];
171
172 // Generate procedure window text.
173 strcpy(text, "Macro Demo()"CR_STR);
174 strcat(text, "\tDoAlert 0, \"Greetings!\""CR_STR);
175 strcat(text, "End"CR_STR);
176
177 return WritePlainTextRecord(fr, kProcedureRecord, text, strlen(text));
178 }
179
180 static int
WriteDemoHistory(CP_FILE_REF fr)181 WriteDemoHistory(CP_FILE_REF fr)
182 {
183 char text[1024];
184 int err;
185
186 // Generate history text.
187 strcpy(text, "// This experiment was created using Igor Pro Tech Note PTN003"CR_STR);
188 strcat(text, "// This tech note shows how to write a packed Igor Pro 3.0 file from your own program."CR_STR);
189
190 if (err = WritePlainTextRecord(fr, kHistoryRecord, text, strlen(text)))
191 return err;
192 return WriteRecordHeader(fr, kGetHistoryRecord, 0, 0);
193 }
194
195 static int
WriteDemoPackedFile(CP_FILE_REF fr)196 WriteDemoPackedFile(CP_FILE_REF fr)
197 {
198 int err;
199
200 if (err = WriteDemoVariablesRecord(fr))
201 return err;
202 if (err = WriteDemoWave1DNumericWaveRecord(fr))
203 return err;
204 if (err = WriteDemoRecreationProcedures(fr))
205 return err;
206 if (err = WriteDemoProcedureWindowProcedures(fr))
207 return err;
208 if (err = WriteDemoHistory(fr))
209 return err;
210 return 0;
211 }
212
213 int
WritePackedFile(const char * packedFilePath)214 WritePackedFile(const char* packedFilePath)
215 {
216 CP_FILE_REF fr; // Ref number for the file we are writing to.
217 char temp[256];
218 int err;
219
220 // Delete test file if it already exists and create a new file.
221 if (err = CPCreateFile(packedFilePath, 1, IGOR_CREATOR_CODE, IGOR_PACKED_FILE_TYPE)) {
222 PrintResult("Create file error", err);
223 return err;
224 }
225
226 if (err = CPOpenFile(packedFilePath, 1, &fr)) {
227 PrintResult("Open file error", err);
228 return err;
229 }
230
231 // Write all of the records to the file.
232 if (err = WriteDemoPackedFile(fr)) {
233 PrintResult("WritePackedFile error", err);
234 return err;
235 }
236
237 if (err = CPCloseFile(fr)) {
238 PrintResult("Close file error", err);
239 return err;
240 }
241
242 sprintf(temp, "\"%s\" written successfully.", packedFilePath);
243 PrintResult(temp, 0);
244
245 return 0;
246 }
247