Commit 25d8d20b5117b6f35d62ce2cdbf4381253d86a45
1 parent
193bb525
added FFT support for HSIproc in Agilent imaging systems
Showing
2 changed files
with
477 additions
and
261 deletions
Show diff stats
1 | +//make sure that this header file is only loaded once | |
2 | +#ifndef STIM_AGILENT_BINARY_H | |
3 | +#define STIM_AGILENT_BINARY_H | |
4 | + | |
5 | +#include <string> | |
6 | +#include <fstream> | |
7 | + | |
8 | +//CUDA | |
9 | +#ifdef CUDA_FOUND | |
10 | + #include <cuda_runtime.h> | |
11 | + #include "cufft.h" | |
12 | + #include <stim/cuda/cudatools/error.h> | |
13 | +#endif | |
14 | + | |
15 | +namespace stim{ | |
16 | + | |
17 | +template<typename T> | |
18 | +class agilent_binary{ | |
19 | + | |
20 | +protected: | |
21 | + std::string fname; | |
22 | + T* ptr; | |
23 | + size_t R[3]; | |
24 | + static const size_t header = 1020; | |
25 | + double Z[2]; | |
26 | + | |
27 | +public: | |
28 | + size_t size(){ | |
29 | + return (size_t)R[0] * (size_t)R[1] * (size_t)R[2]; | |
30 | + } | |
31 | + | |
32 | + size_t bytes(){ | |
33 | + return size() * sizeof(T); | |
34 | + } | |
35 | + void alloc(){ | |
36 | + ptr = (T*) malloc(bytes()); | |
37 | + } | |
38 | + void alloc(short x, short y, short z){ | |
39 | + R[0] = x; | |
40 | + R[1] = y; | |
41 | + R[2] = z; | |
42 | + alloc(); | |
43 | + } | |
44 | + | |
45 | + void deep_copy(agilent_binary<T>* dst, const agilent_binary<T>* src){ | |
46 | + dst->alloc(src->R[0], src->R[1], src->R[2]); //allocate memory | |
47 | + memcpy(dst->ptr, src->ptr, bytes()); //copy the data | |
48 | + memcpy(dst->Z, src->Z, sizeof(double) * 2); //copy the data z range | |
49 | + } | |
50 | + | |
51 | + agilent_binary(){ | |
52 | + memset(R, 0, sizeof(short) * 3); //set the resolution to zero | |
53 | + ptr = NULL; | |
54 | + } | |
55 | + | |
56 | + /// Constructor with resolution | |
57 | + agilent_binary(short x, short y, short z){ | |
58 | + alloc(x, y, z); | |
59 | + } | |
60 | + | |
61 | + /// Constructor with filename | |
62 | + agilent_binary(std::string filename){ | |
63 | + ptr = NULL; | |
64 | + load(filename); | |
65 | + } | |
66 | + | |
67 | + /// Copy constructor | |
68 | + agilent_binary(const agilent_binary<T> &obj){ | |
69 | + deep_copy(this, &obj); | |
70 | + } | |
71 | + | |
72 | + agilent_binary<T>& operator=(const agilent_binary<T> rhs){ | |
73 | + if(this != &rhs){ //check for self-assignment | |
74 | + deep_copy(this, &rhs); //make a deep copy | |
75 | + } | |
76 | + return *this; //return the result | |
77 | + } | |
78 | + | |
79 | + ~agilent_binary(){ | |
80 | + free(ptr); | |
81 | + } | |
82 | + | |
83 | + void load(std::string filename){ | |
84 | + if(ptr != NULL) free(ptr); //if memory has been allocated, free it | |
85 | + | |
86 | + fname = filename; //save the filename | |
87 | + | |
88 | + short x, y, z; | |
89 | + | |
90 | + std::ifstream infile(fname, std::ios::binary); //open the input file | |
91 | + infile.seekg(9, std::ios::beg); //seek past 9 bytes from the beginning of the file | |
92 | + | |
93 | + infile.read((char*)(&z), 2); //read two bytes of data (the number of samples is stored as a 16-bit integer) | |
94 | + | |
95 | + infile.seekg(13, std::ios::cur); //skip another 13 bytes | |
96 | + infile.read((char*)(&x), 2); //read the X and Y dimensions | |
97 | + infile.read((char*)(&y), 2); | |
98 | + | |
99 | + infile.seekg(header, std::ios::beg); //seek to the start of the data | |
100 | + | |
101 | + alloc(x, y, z); | |
102 | + ptr = (T*) malloc(bytes()); //allocate space for the data | |
103 | + infile.read((char*)ptr, bytes()); //read the data | |
104 | + infile.close(); | |
105 | + } | |
106 | + | |
107 | + void save(std::string filename){ | |
108 | + std::ofstream outfile(filename, std::ios::binary); //create an output file | |
109 | + | |
110 | + char zero = 0; | |
111 | + for(size_t i = 0; i < 9; i++) outfile.write(&zero, 1); //write 9 zeros | |
112 | + outfile.write((char*)&R[0], 2); | |
113 | + for(size_t i = 0; i < 13; i++) outfile.write(&zero, 1); //write 13 zeros | |
114 | + outfile.write((char*)&R[1], 2); | |
115 | + outfile.write((char*)&R[2], 2); | |
116 | + for(size_t i = 0; i < 992; i++) outfile.write(&zero, 1); //write 992 zeros | |
117 | + //char zerovec[1020]; | |
118 | + //outfile.write((char*)zerovec, 1020); | |
119 | + | |
120 | + size_t b = bytes(); | |
121 | + outfile.write((char*)ptr, b); //write the data to the output file | |
122 | + outfile.close(); | |
123 | + } | |
124 | + | |
125 | + stim::envi_header create_header(){ | |
126 | + stim::envi_header header; | |
127 | + header.samples = R[0]; | |
128 | + header.lines = R[1]; | |
129 | + header.bands = R[2]; | |
130 | + | |
131 | + double z_delta = (double)(Z[1] - Z[0]) / (double)(R[2] - 1); | |
132 | + header.wavelength.resize(R[2]); | |
133 | + for(size_t i = 0; i < R[2]; i++) | |
134 | + header.wavelength[i] = i * z_delta + Z[0]; | |
135 | + | |
136 | + return header; | |
137 | + } | |
138 | + | |
139 | + /// Calculate the absorbance spectrum from the transmission spectrum given a background | |
140 | + void absorbance(stim::agilent_binary<T>* background){ | |
141 | + size_t N = size(); //calculate the number of values to be ratioed | |
142 | + if(N != background->size()){ | |
143 | + std::cerr<<"ERROR in stim::agilent_binary::absorbance() - transmission image size doesn't match background"<<std::endl; | |
144 | + exit(1); | |
145 | + } | |
146 | + for(size_t i = 0; i < N; i++) | |
147 | + ptr[i] = -log10(ptr[i] / background->ptr[i]); | |
148 | + } | |
149 | + | |
150 | +#ifdef CUDA_FOUND | |
151 | + /// Perform an FFT and return a binary file with bands in the specified range | |
152 | + agilent_binary<T> fft(float band_min, float band_max){ | |
153 | + auto total_start = std::chrono::high_resolution_clock::now(); | |
154 | + | |
155 | + auto start = std::chrono::high_resolution_clock::now(); | |
156 | + T* cpu_data = (T*) malloc( bytes() ); //allocate space for the transposed data | |
157 | + for(size_t b = 0; b < R[2]; b++){ | |
158 | + for(size_t x = 0; x < R[0] * R[1]; x++){ | |
159 | + cpu_data[x * R[2] + b] = ptr[b * R[0] * R[1] + x]; | |
160 | + } | |
161 | + } | |
162 | + auto end = std::chrono::high_resolution_clock::now(); | |
163 | + std::chrono::duration<double> diff = end-start; | |
164 | + // std::cout << "Transpose data: " << diff.count() << " s\n"; | |
165 | + | |
166 | + start = std::chrono::high_resolution_clock::now(); | |
167 | + cufftHandle plan; //allocate space for a cufft plan | |
168 | + cufftReal* gpu_data; //create a pointer to the data | |
169 | + size_t batch = R[0] * R[1]; //calculate the batch size (X * Y) | |
170 | + HANDLE_ERROR(cudaMalloc((void**)&gpu_data, bytes())); //allocate space on the GPU | |
171 | + HANDLE_ERROR(cudaMemcpy(gpu_data, cpu_data, bytes(), cudaMemcpyHostToDevice)); //copy the data to the GPU | |
172 | + cufftComplex* gpu_fft; | |
173 | + HANDLE_ERROR(cudaMalloc((void**)&gpu_fft, R[0] * R[1] * (R[2]/2 + 1) * sizeof(cufftComplex))); | |
174 | + end = std::chrono::high_resolution_clock::now(); | |
175 | + diff = end-start; | |
176 | + //std::cout << "Allocate/copy: " << diff.count() << " s\n"; | |
177 | + | |
178 | + start = std::chrono::high_resolution_clock::now(); | |
179 | + int N[1]; //create an array with the interferogram size (required for cuFFT input) | |
180 | + N[0] = R[2]; //set the only array value to the interferogram size | |
181 | + if(cufftPlanMany(&plan, 1, N, NULL, 1, R[2], NULL, 1, R[2], CUFFT_R2C, batch) != CUFFT_SUCCESS){ | |
182 | + std::cout<<"cuFFT Error: unable to create 1D plan."<<std::endl; | |
183 | + exit(1); | |
184 | + } | |
185 | + end = std::chrono::high_resolution_clock::now(); | |
186 | + diff = end-start; | |
187 | + //std::cout << "Create a plan: " << diff.count() << " s\n"; | |
188 | + | |
189 | + start = std::chrono::high_resolution_clock::now(); | |
190 | + if (cufftExecR2C(plan, gpu_data, gpu_fft) != CUFFT_SUCCESS){ //execute the (implicitly forward) transform | |
191 | + std::cout<<"CUFFT error: ExecR2C Forward failed"; | |
192 | + exit(1); | |
193 | + } | |
194 | + end = std::chrono::high_resolution_clock::now(); | |
195 | + diff = end-start; | |
196 | + //std::cout << "Perform FFT: " << diff.count() << " s\n"; | |
197 | + | |
198 | + start = std::chrono::high_resolution_clock::now(); | |
199 | + std::complex<T>* cpu_fft = (std::complex<T>*) malloc( R[0] * R[1] * (R[2]/2+1) * sizeof(std::complex<T>) ); | |
200 | + HANDLE_ERROR(cudaMemcpy(cpu_fft, gpu_fft, R[0] * R[1] * (R[2]/2+1) * sizeof(cufftComplex), cudaMemcpyDeviceToHost)); //copy data from the host to the device | |
201 | + | |
202 | + double int_delta = 0.00012656; //interferogram sample spacing in centimeters | |
203 | + double int_length = int_delta * R[2]; //interferogram length in centimeters | |
204 | + double fft_delta = 1/int_length; //spectrum spacing (in inverse centimeters, wavenumber | |
205 | + | |
206 | + size_t start_i = std::ceil(band_min / fft_delta); //calculate the first band to store | |
207 | + size_t size_i = std::floor(band_max / fft_delta) - start_i; //calculate the number of bands to store | |
208 | + size_t end_i = start_i + size_i; //last band number | |
209 | + agilent_binary<T> result(R[0], R[1], size_i); | |
210 | + result.Z[0] = start_i * fft_delta; //set the range for the FFT result | |
211 | + result.Z[1] = end_i * fft_delta; | |
212 | + | |
213 | + for(size_t b = start_i; b < end_i; b++){ | |
214 | + for(size_t x = 0; x < R[0] * R[1]; x++){ | |
215 | + result.ptr[(b - start_i) * R[0] * R[1] + x] = abs(cpu_fft[x * (R[2]/2+1) + b]); | |
216 | + } | |
217 | + } | |
218 | + end = std::chrono::high_resolution_clock::now(); | |
219 | + diff = end-start; | |
220 | + //std::cout << "Transpose/Crop: " << diff.count() << " s\n"; | |
221 | + | |
222 | + auto total_end = std::chrono::high_resolution_clock::now(); | |
223 | + diff = total_end-total_start; | |
224 | + | |
225 | + cufftDestroy(plan); | |
226 | + HANDLE_ERROR(cudaFree(gpu_data)); | |
227 | + HANDLE_ERROR(cudaFree(gpu_fft)); | |
228 | + free(cpu_data); | |
229 | + free(cpu_fft); | |
230 | + | |
231 | + return result; | |
232 | + } | |
233 | +#endif | |
234 | + | |
235 | +}; | |
236 | + | |
237 | +} | |
238 | + | |
239 | +#endif | |
0 | 240 | \ No newline at end of file | ... | ... |
stim/parser/filename.h
... | ... | @@ -2,218 +2,292 @@ |
2 | 2 | #define STIM_FILENAME_H |
3 | 3 | |
4 | 4 | #include <stdio.h> /* defines FILENAME_MAX */ |
5 | +#include <sstream> | |
6 | +#include <vector> | |
7 | +#include <algorithm> | |
8 | +#include <iostream> | |
9 | +#include <iomanip> | |
10 | + | |
11 | +#include <stim/parser/parser.h> | |
12 | + | |
13 | +// set OS dependent defines, including: | |
14 | +// 1) path division character ('/' or '\') used for output only | |
15 | +// 2) command for getting the current working directory | |
16 | +// 3) header files for getting the current working directory | |
17 | +// 4) include BOOST filesystem class if compiling on GCC | |
18 | +#define STIM_DIV '/' | |
5 | 19 | #ifdef _WIN32 |
6 | 20 | #include <windows.h> |
7 | - #include <direct.h> | |
8 | - #define GetCurrentDir _getcwd | |
9 | - #define STIM_FILENAME_DIV '/' | |
21 | + #include <direct.h> | |
22 | + #define GetCurrentDir _getcwd | |
23 | + #define STIM_FILENAME_DIV '\\' | |
10 | 24 | #else |
11 | - #include <unistd.h> | |
12 | - #define GetCurrentDir getcwd | |
25 | + #ifdef BOOST_PRECOMPILED | |
26 | + #include <boost/filesystem.hpp> | |
27 | + #endif | |
28 | + #include <unistd.h> | |
29 | + #define GetCurrentDir getcwd | |
13 | 30 | #define STIM_FILENAME_DIV '/' |
14 | 31 | #endif |
15 | 32 | |
16 | -#include <string> | |
17 | -#include <sstream> | |
18 | -#include <iomanip> | |
19 | -#include <vector> | |
20 | -#include <stack> | |
21 | -#include <algorithm> | |
22 | -#include <iostream> | |
23 | - | |
24 | -#include "../parser/parser.h" | |
25 | -#ifdef BOOST_PRECOMPILED | |
26 | -#include <boost/filesystem.hpp> | |
27 | -#endif | |
28 | 33 | namespace stim{ |
29 | 34 | |
30 | -//filename class designed to work with both Windows and Unix | |
35 | +class filepath{ | |
36 | +protected: | |
37 | + std::string _drive; //drive on which the file is located (used for Windows) | |
38 | + std::vector<std::string> _path; //path for the specified file (list of hierarchical directories) | |
31 | 39 | |
32 | -class filename{ | |
40 | + /// replaces win32 dividers with the Linux standard (used internally by default) | |
41 | + std::string unix_div(std::string s) { | |
42 | + std::replace( s.begin(), s.end(), '\\', '/'); | |
43 | + return s; | |
44 | + } | |
33 | 45 | |
34 | -private: | |
35 | - void init(){ | |
46 | + /// gets the directory hierarchy for the current working directory | |
47 | + static std::string cwd(){ | |
48 | + char cCurrentPath[FILENAME_MAX]; | |
36 | 49 | |
37 | - absolute = false; | |
50 | + if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath))){ | |
51 | + std::cout<<"ERROR getting current working directory."<<std::endl; | |
52 | + exit(1); | |
53 | + } | |
38 | 54 | |
55 | + std::stringstream ss; | |
56 | + ss<<cCurrentPath; | |
57 | + return ss.str(); | |
39 | 58 | } |
40 | 59 | |
41 | -protected: | |
60 | + /// convert a relative path to an absolute path | |
61 | + void get_absolute(std::string &drive, std::vector<std::string> &absolute, std::vector<std::string> relative){ | |
42 | 62 | |
43 | - std::string drive; //drive letter (for Windows) | |
44 | - std::vector<std::string> path; //directory hierarchy | |
45 | - std::string prefix; //file prefix (without extension) | |
46 | - std::string ext; //file extension | |
63 | + std::string current = cwd(); //get the current directory as a string | |
47 | 64 | |
48 | - bool absolute; //filename is an absolute path | |
65 | + std::string current_drive; | |
66 | + std::vector<std::string> current_dir; | |
67 | + parse_path(current_drive, current_dir, current); //get the current drive and directories | |
49 | 68 | |
50 | - //replaces win32 dividers with the Linux standard | |
51 | - std::string unix_div(std::string s) { | |
52 | - std::replace( s.begin(), s.end(), '\\', '/'); | |
53 | - return s; | |
54 | - } | |
55 | - | |
56 | - //break up a filename into a prefix and extension | |
57 | - void parse_name(std::string fname){ | |
69 | + // step through each directory in the relative path, adjusting the current directory | |
70 | + // index depending on whether the relative path is specified with '.' or '..' | |
71 | + int current_i = (int)current_dir.size() - 1; | |
72 | + int relative_i; | |
73 | + for(relative_i = 0; relative_i < relative.size(); relative_i++){ | |
74 | + if(relative[relative_i] == "..") current_i--; | |
75 | + else if(relative[relative_i] != ".") break; | |
76 | + } | |
77 | + if(current_i < 0){ | |
78 | + std::cerr<<"ERROR stim::filepath - relative path is incompatible with working directory"<<std::endl; | |
79 | + exit(1); | |
80 | + } | |
58 | 81 | |
59 | - //find the extension | |
60 | - size_t xpos = fname.find_last_of('.'); //find the position of the extension period (if there is one) | |
61 | - if(xpos != std::string::npos){ //split the prefix and extension | |
62 | - prefix = fname.substr(0, xpos); | |
63 | - ext = fname.substr(xpos + 1); | |
82 | + absolute.clear(); | |
83 | + for(size_t i = 0; i <= current_i; i++){ | |
84 | + absolute.push_back(current_dir[i]); | |
85 | + } | |
86 | + for(size_t i = relative_i; i < relative.size(); i++){ | |
87 | + absolute.push_back(relative[i]); | |
64 | 88 | } |
65 | - else | |
66 | - prefix = fname; | |
67 | 89 | } |
68 | 90 | |
69 | - //parse a file locator string | |
70 | - void parse(std::string loc){ | |
71 | - if(loc.size() == 0) return; | |
72 | - | |
73 | - loc = unix_div(loc); | |
74 | - | |
75 | - //determine the drive (if Windows) | |
76 | - drive = ""; | |
77 | - #ifdef _WIN32 | |
78 | - //if the second character is a colon, the character right before it is the drive | |
79 | - if(loc[1] == ':'){ | |
80 | - absolute = true; //this is an absolute path | |
81 | - drive = loc[0]; //copy the drive letter | |
82 | - loc = loc.substr(3); //remove the drive information from the locator string | |
91 | + /// Parses a directory string into a drive (NULL if not Windows) and list of hierarchical directories | |
92 | + /// Returns true if the path is relative, false if it is absolute | |
93 | + void parse_path(std::string &drive, std::vector<std::string> &absolute, std::string dir){ | |
94 | + drive = ""; //initialize the drive to NULL (it will stay that way for Windows) | |
95 | + std::vector<std::string> path; | |
96 | + bool relative = true; //the default path is relative | |
97 | + | |
98 | + if(dir.length() == 0) return; //return if the file locator is empty | |
99 | + std::string unix_dir = unix_div(dir); //replace any Windows division characters with Unix | |
100 | + | |
101 | + if(unix_dir.length() > 1 && unix_dir[1] == ':'){ //if a drive identifier is given | |
102 | + if(unix_dir[0] > 64 && unix_dir[0] < 91) //if the drive letter is upper case | |
103 | + _drive = unix_dir[0] + 32; //convert it to lower case | |
104 | + else if(unix_dir[0] > 96 && unix_dir[0] < 123) //if the drive character is lower case | |
105 | + _drive = unix_dir[0]; //store it as-is | |
106 | + else{ //otherwise throw an error | |
107 | + std::cerr<<"ERROR stim::filename - drive letter is invalid: "<<unix_dir[0]<<std::endl; | |
108 | + exit(1); | |
83 | 109 | } |
84 | - #else | |
85 | - if(loc[0] == STIM_FILENAME_DIV){ | |
86 | - absolute = true; | |
87 | - loc = loc.substr(1); | |
88 | - } | |
89 | - #endif | |
90 | - | |
91 | - //determine the file name | |
92 | - std::string fname = loc.substr( loc.find_last_of('/') + 1 ); //find the file name (including extension) | |
110 | + unix_dir = unix_dir.substr(2, unix_dir.length()-2); //extract the directory structure | |
111 | + } | |
93 | 112 | |
94 | - //parse the file name | |
95 | - parse_name(fname); | |
113 | + if(unix_dir.front() == '/'){ //if there is a leading slash | |
114 | + relative = false; //the path is not relative | |
115 | + unix_dir = unix_dir.substr(1, unix_dir.length() - 1); //remove the slash | |
116 | + } | |
117 | + if(unix_dir.back() == '/') | |
118 | + unix_dir = unix_dir.substr(0, unix_dir.length() - 1); | |
96 | 119 | |
97 | - //find the directory hierarchy | |
98 | - std::string dir = loc.substr(0, loc.find_last_of('/') + 1 ); | |
99 | - path = stim::parser::split(dir, '/'); | |
120 | + path = stim::parser::split(unix_dir, '/'); //split up the directory structure | |
121 | + | |
122 | + if(relative) | |
123 | + get_absolute(drive, absolute, path); | |
124 | + else | |
125 | + absolute = path; | |
100 | 126 | } |
101 | 127 | |
102 | -public: | |
128 | + | |
103 | 129 | |
104 | - filename(){ | |
105 | - init(); | |
130 | +public: | |
131 | + filepath(){ | |
132 | + _drive = ""; | |
106 | 133 | } |
107 | 134 | |
108 | - filename(std::string loc){ | |
109 | - init(); | |
110 | - parse(loc); | |
135 | + filepath(const stim::filepath& p){ | |
136 | + *this = p; | |
111 | 137 | } |
112 | 138 | |
139 | + filepath(const std::string s){ | |
140 | + parse_path(_drive, _path, s); | |
141 | + } | |
113 | 142 | |
114 | - /// Outputs the file name (including prefix and extension) | |
115 | - std::string get_name(){ | |
116 | - if(prefix == "" && ext == "") | |
117 | - return ""; | |
118 | - else | |
119 | - return prefix + "." + ext; | |
143 | + stim::filepath& operator=(const std::string s){ | |
144 | + parse_path(_drive, _path, s); //parse the string to get the drive and relative path | |
145 | + return *this; | |
120 | 146 | } |
121 | 147 | |
122 | - /// Output the file extension only (usually three characters after a '.') | |
123 | - std::string get_extension(){ | |
124 | - return ext; | |
148 | + std::string str(){ | |
149 | + std::stringstream ss; | |
150 | + if(_drive != "") //if a drive letter is specified | |
151 | + ss<<_drive<<":"; //add it to the string | |
152 | + for(size_t i = 0; i < _path.size(); i++) | |
153 | + ss<<STIM_FILENAME_DIV<<_path[i]; | |
154 | + ss<<STIM_FILENAME_DIV; | |
155 | + return ss.str(); | |
156 | + } | |
157 | +}; //end filepath | |
158 | + | |
159 | +class filename : public filepath{ | |
160 | +protected: | |
161 | + std::string _prefix; //filename prefix | |
162 | + std::string _extension; //filename extension | |
163 | + | |
164 | + void set_filename(std::string fname){ | |
165 | + size_t ext_i = fname.find_last_of('.'); //calculate the index of the '.' | |
166 | + if(ext_i != std::string::npos){ //if there is an extension | |
167 | + _prefix = fname.substr(0, ext_i); //store the prefix | |
168 | + _extension = fname.substr(ext_i + 1, fname.size() - ext_i - 1); //store the extension | |
169 | + } | |
170 | + else //otherwise just store the prefix | |
171 | + _prefix = fname; | |
125 | 172 | } |
126 | 173 | |
127 | - /// Output the file prefix only (name before the extension) | |
128 | - std::string get_prefix(){ | |
129 | - return prefix; | |
174 | +public: | |
175 | + filename(){} | |
176 | + | |
177 | + filename(stim::filepath p, std::string fname) : stim::filepath(p){ | |
178 | + set_filename(fname); | |
130 | 179 | } |
131 | 180 | |
132 | - /// Output the entire path (not including the filename) | |
133 | - /// ex. "c:\this\is\the\directory\" | |
134 | - std::string dir(){ | |
135 | - std::stringstream ss; | |
181 | + stim::filename& operator=(const std::string s){ | |
182 | + std::string unix_s = unix_div(s); //convert dividers to unix | |
183 | + size_t name_i = unix_s.find_last_of('/'); //find the index of the last divider | |
136 | 184 | |
137 | - //if the path is absolute | |
138 | - if(absolute){ | |
139 | - //output the drive letter if in Windows | |
140 | - #ifdef _WIN32 | |
141 | - ss<<drive<<":"; | |
142 | - #endif | |
143 | - ss<<STIM_FILENAME_DIV; | |
185 | + if(name_i == std::string::npos){ //if there is no divider, this is just a filename | |
186 | + unix_s = "./" + unix_s; //append a ./ to the beginning so that the working directory is used | |
187 | + name_i = 1; | |
144 | 188 | } |
145 | 189 | |
146 | - //output the directory | |
147 | - for(unsigned int d = 0; d < path.size(); d++) | |
148 | - ss<<path[d]<<STIM_FILENAME_DIV; | |
190 | + name_i++; | |
149 | 191 | |
150 | - return ss.str(); | |
151 | 192 | |
193 | + std::string filename = unix_s.substr(name_i, unix_s.size() - name_i); //extract the filename | |
194 | + std::string filepath = unix_s.substr(0, name_i-1); //extract the filepath | |
195 | + | |
196 | + filepath::operator=(filepath); //parse and store the file path | |
197 | + | |
198 | + set_filename(filename); | |
199 | + return *this; | |
152 | 200 | } |
153 | 201 | |
154 | - void clear() | |
155 | - { | |
156 | - drive = ""; //drive letter (for Windows) | |
157 | - path.resize(0); | |
158 | - prefix= ""; //file prefix (without extension) | |
159 | - ext = ""; //file extension | |
202 | + filename(std::string s){ | |
203 | + operator=(s); | |
160 | 204 | } |
161 | 205 | |
162 | - /// Output the entire string, including the path and filename | |
163 | - /// ex. "c:\this\is\a\directory\file.txt" | |
206 | + | |
207 | + | |
164 | 208 | std::string str(){ |
165 | - std::stringstream ss; //create a string stream | |
166 | - ss<<dir()<<get_name(); //push the directory and filename to that stream | |
167 | - return ss.str(); //convert the stream to a string and return it | |
209 | + std::stringstream ss; | |
210 | + ss<<filepath::str()<<_prefix; | |
211 | + if(_extension.size() != 0) | |
212 | + ss<<"."<<_extension; | |
213 | + return ss.str(); | |
168 | 214 | } |
169 | 215 | |
170 | - //***************************************************************************************************************** | |
171 | - // output is the directory and the prefix and the extension of the files, which are looking for in that directory. | |
172 | - /// David: I have no idea what this is doing. It looks identical to dir() | |
173 | - std::string dir_fname(){ | |
174 | - std::stringstream ss; | |
216 | + /// Create a matching file locator with a prefix s | |
217 | + stim::filename prefix(std::string s){ | |
218 | + stim::filename result = *this; | |
219 | + result._prefix = s; | |
220 | + return result; | |
221 | + } | |
175 | 222 | |
176 | - //if the path is absolute | |
177 | - if(absolute){ | |
178 | - //output the drive letter if in Windows | |
179 | - #ifdef _WIN32 | |
180 | - ss<<drive<<":"; | |
181 | - #endif | |
182 | - ss<<STIM_FILENAME_DIV; | |
183 | - } | |
223 | + std::string prefix(){ | |
224 | + return _prefix; | |
225 | + } | |
184 | 226 | |
227 | + std::string get_prefix(){ | |
228 | + return _prefix; | |
229 | + } | |
185 | 230 | |
186 | - for(unsigned int d = 0; d < path.size(); d++) | |
187 | - ss<<path[d]<<STIM_FILENAME_DIV; | |
188 | - ss<<get_name(); | |
231 | + /// Create a matching file locator with the extension changed to s | |
232 | + stim::filename extension(std::string s){ | |
233 | + stim::filename result = *this; | |
234 | + result._extension = s; | |
235 | + return result; | |
236 | + } | |
189 | 237 | |
190 | - return ss.str(); | |
238 | + std::string extension(){ | |
239 | + return _extension; | |
240 | + } | |
191 | 241 | |
242 | + stim::filename fname(std::string s){ | |
243 | + stim::filename result = *this; | |
244 | + size_t ext_i = s.find_last_of('.'); //calculate the index of the '.' | |
245 | + if(ext_i != std::string::npos){ //if there is an extension | |
246 | + result._prefix = s.substr(0, ext_i); //store the prefix | |
247 | + result._extension = s.substr(ext_i + 1, s.size() - ext_i - 1); //store the extension | |
248 | + } | |
249 | + else //otherwise just store the prefix | |
250 | + result._prefix = s; | |
251 | + return result; | |
192 | 252 | } |
193 | 253 | |
194 | - // output is the directory and the name of the file which are found in that given directory | |
195 | - std::string f_name(std::string file_name){ | |
196 | - std::stringstream ss; | |
254 | + /// create a matching file locator with the path changed to s | |
255 | + stim::filename path(std::string s){ | |
256 | + stim::filename result = *this; | |
257 | + result.parse_path(result._drive, result._path, s); | |
258 | + return result; | |
259 | + } | |
197 | 260 | |
198 | - if(absolute){ //if the path is absolute | |
199 | - #ifdef _WIN32 | |
200 | - ss<<drive<<":"; //output the drive letter if in Windows | |
201 | - #endif | |
202 | - ss<<STIM_FILENAME_DIV; //output a path divider | |
203 | - } | |
261 | + std::string path(){ | |
262 | + return filepath::str(); | |
263 | + } | |
204 | 264 | |
205 | - for(unsigned int d = 0; d < path.size(); d++) //for each directory in the current path | |
206 | - ss<<path[d]<<STIM_FILENAME_DIV; //add that directory, interspersing path dividers | |
265 | + /// Casting operator, casts to a string | |
266 | + operator std::string(){ | |
267 | + return str(); | |
268 | + } | |
207 | 269 | |
208 | - stim::filename fn = file_name; | |
209 | - std::string fn_prefix = fn.prefix; | |
210 | - std::string fn_ext = fn.ext; | |
211 | - ss<<fn_prefix + '.' + fn_ext; | |
270 | + /// This function replaces a wildcard in the prefix with the specified string | |
271 | + stim::filename insert(std::string str){ | |
212 | 272 | |
213 | - return ss.str(); | |
273 | + stim::filename result = *this; //initialize the result filename to the current filename | |
274 | + size_t loc = result._prefix.find('*'); //find a wild card in the string | |
275 | + if(loc == std::string::npos) //if a wildcard isn't found | |
276 | + result._prefix += str; //append the value to the prefix | |
277 | + else | |
278 | + result._prefix.replace(loc, 1, str); //replace the wildcard with the string | |
279 | + return result; //return the result | |
280 | + } | |
281 | + | |
282 | + /// This function replaces a wildcard in the prefix with the specified integer (with a padding of n) | |
283 | + stim::filename insert(size_t i, size_t n = 2){ | |
214 | 284 | |
285 | + std::stringstream ss; | |
286 | + ss << std::setw(n) << std::setfill('0') << i; | |
287 | + return insert(ss.str()); | |
215 | 288 | } |
216 | 289 | |
290 | + | |
217 | 291 | /// Returns a list of files using the current filename as a template. |
218 | 292 | /// For example: |
219 | 293 | /// C:\this\is\a\path\file*.txt |
... | ... | @@ -223,28 +297,33 @@ public: |
223 | 297 | //the Unix version requires Boost |
224 | 298 | |
225 | 299 | #ifdef _WIN32 |
226 | - stim::filename filepath(dir_fname()); //initialize filepath with the mask | |
227 | 300 | |
228 | 301 | HANDLE hFind = INVALID_HANDLE_VALUE; //allocate data structures for looping through files |
229 | 302 | WIN32_FIND_DATAA FindFileData; |
230 | 303 | std::vector<stim::filename> file_list; //initialize a list to hold all matching filenames |
231 | 304 | |
232 | - hFind = FindFirstFileA((filepath.str().c_str()), &FindFileData); //find the first file that matches the specified file path | |
305 | + std::string path_string = str(); | |
306 | + hFind = FindFirstFileA(path_string.c_str(), &FindFileData); //find the first file that matches the specified file path | |
233 | 307 | |
234 | 308 | if (hFind == INVALID_HANDLE_VALUE) { //if there are no matching files |
235 | - printf ("Invalid file handle. Error is %u.\n", GetLastError()); //print an error | |
309 | + //printf ("Invalid file handle. Error is %u.\n", GetLastError()); //print an error | |
310 | + return file_list; | |
236 | 311 | } |
237 | 312 | else { |
238 | 313 | std::string file_name = FindFileData.cFileName; //save the file name |
239 | - std::string file_path = dir(); //the file is in the specified directory, so save it | |
314 | + std::string file_path = path(); //the file is in the specified directory, so save it | |
240 | 315 | stim::filename current_file(file_path + file_name); //create a stim::filename structure representing this file |
241 | - file_list.push_back(current_file); //push the new stim::filename to the file list | |
316 | + if(!(FindFileData.cFileName[0] == '.' && FindFileData.cFileName[1] == '\0')) | |
317 | + file_list.push_back(current_file); //push the new stim::filename to the file list | |
318 | + | |
242 | 319 | |
243 | 320 | // List all the other files in the directory. |
244 | 321 | while (FindNextFileA(hFind, &FindFileData) != 0){ //iterate until there are no more matching files |
245 | - file_name = FindFileData.cFileName; //save the next file | |
246 | - current_file = (f_name(file_name)); //append the directory | |
247 | - file_list.push_back(current_file); //push it to the list | |
322 | + if(!(FindFileData.cFileName[0] == '.' && FindFileData.cFileName[1] == '.' && FindFileData.cFileName[2] == '\0')){ //account for the possibility of the '..' filename | |
323 | + file_name = FindFileData.cFileName; //save the next file | |
324 | + current_file = fname(file_name); //append the directory | |
325 | + file_list.push_back(current_file); //push it to the list | |
326 | + } | |
248 | 327 | } |
249 | 328 | FindClose(hFind); //close the file data structure |
250 | 329 | } |
... | ... | @@ -287,108 +366,6 @@ public: |
287 | 366 | #endif |
288 | 367 | |
289 | 368 | } |
290 | - //************************************************************************************************** | |
291 | - | |
292 | - //gets the current working directory | |
293 | - static stim::filename cwd(){ | |
294 | - | |
295 | - | |
296 | - char cCurrentPath[FILENAME_MAX]; | |
297 | - | |
298 | - if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath))){ | |
299 | - std::cout<<"ERROR getting current working directory."<<std::endl; | |
300 | - exit(1); | |
301 | - } | |
302 | - | |
303 | - std::cout<<cCurrentPath<<std::endl; | |
304 | - return stim::filename(std::string(cCurrentPath) + STIM_FILENAME_DIV); | |
305 | - } | |
306 | - | |
307 | - void set_name(std::string fname){ | |
308 | - parse_name(fname); | |
309 | - } | |
310 | - | |
311 | - //append a string to the filename and return a new filename | |
312 | - stim::filename append(std::string s){ | |
313 | - stim::filename result = *this; //create a new filename, copy the current filename | |
314 | - result.prefix = prefix + s; //append the string to the filename | |
315 | - return result; | |
316 | - } | |
317 | - | |
318 | - //get a path relative to the current one | |
319 | - stim::filename get_relative(std::string rel){ | |
320 | - | |
321 | - std::vector<std::string> rel_path = stim::parser::split(rel, STIM_FILENAME_DIV); | |
322 | - | |
323 | - //if the relative path doesn't contain a file, add a blank string to be used as the filename | |
324 | - if(rel[rel.size()-1] == STIM_FILENAME_DIV) | |
325 | - rel_path.push_back(""); | |
326 | - | |
327 | - //create a stack representing the current absolute path | |
328 | - std::stack<std::string, std::vector<std::string> > s(path); | |
329 | - | |
330 | - //for each token in the relative path | |
331 | - for(int d=0; d<rel_path.size() - 1; d++){ | |
332 | - | |
333 | - //if the token is a double-dot, pop a directory off of the stack | |
334 | - if(rel_path[d] == "..") | |
335 | - s.pop(); | |
336 | - else | |
337 | - s.push(rel_path[d]); | |
338 | - } | |
339 | - | |
340 | - std::string* end = &s.top() + 1; | |
341 | - std::string* begin = end - s.size(); | |
342 | - std::vector<std::string> result_path(begin, end); | |
343 | - | |
344 | - //create a new path to be returned | |
345 | - stim::filename result = *this; | |
346 | - result.path = result_path; | |
347 | - result.set_name(rel_path.back()); | |
348 | - | |
349 | - return result; | |
350 | - } | |
351 | - | |
352 | - /// This function replaces a wildcard in the prefix with the specified string | |
353 | - stim::filename insert(std::string str){ | |
354 | - | |
355 | - stim::filename result = *this; //initialize the result filename to the current filename | |
356 | - size_t loc = result.prefix.find('*'); //find a wild card in the string | |
357 | - if(loc == std::string::npos) //if a wildcard isn't found | |
358 | - result.prefix += str; //append the value to the prefix | |
359 | - else | |
360 | - result.prefix.replace(loc, 1, str); //replace the wildcard with the string | |
361 | - return result; //return the result | |
362 | - } | |
363 | - | |
364 | - stim::filename insert(size_t i, size_t n = 2){ | |
365 | - | |
366 | - std::stringstream ss; | |
367 | - ss << std::setw(n) << std::setfill('0') << i; | |
368 | - return insert(ss.str()); | |
369 | - } | |
370 | - | |
371 | - bool is_relative(){ | |
372 | - return !absolute; | |
373 | - } | |
374 | - | |
375 | - bool is_absolute(){ | |
376 | - return absolute; | |
377 | - } | |
378 | - | |
379 | - | |
380 | - | |
381 | - | |
382 | - | |
383 | - | |
384 | - | |
385 | - | |
386 | - | |
387 | -}; | |
388 | - | |
389 | - | |
390 | -} //end namespace stim | |
391 | - | |
392 | - | |
393 | -#endif | |
394 | - | |
369 | +}; //end filename | |
370 | +} //end namespace stim | |
371 | +#endif | |
395 | 372 | \ No newline at end of file | ... | ... |