diff --git a/runtime_data/openalpr.conf b/runtime_data/openalpr.conf index c88437e..38159ec 100644 --- a/runtime_data/openalpr.conf +++ b/runtime_data/openalpr.conf @@ -1,6 +1,5 @@ [common] - ocr_img_size_percent = 1.33333333 state_id_img_size_percent = 2.0 @@ -26,20 +25,18 @@ postprocess_min_characters = 4 postprocess_max_characters = 10 [debug] -general = 0 -timing = 0 -state_id = 0 -plate_lines = 0 +general = 0 +timing = 0 +state_id = 0 +plate_lines = 0 plate_corners = 0 -char_regions = 0 -char_segment = 0 +char_regions = 0 +char_segment = 0 char_analysis = 0 -color_filter = 0 -ocr = 0 -postprocess = 0 -show_images = 0 - - +color_filter = 0 +ocr = 0 +postprocess = 0 +show_images = 0 ;;; Country Specific variables ;;;; @@ -70,7 +67,6 @@ template_max_height_px = 60 plateline_sensitivity_vertical = 25 plateline_sensitivity_horizontal = 45 - ; Regions smaller than this will be disqualified min_plate_size_width_px = 70 min_plate_size_height_px = 35 @@ -85,7 +81,6 @@ char_analysis_height_range = 0.15 char_analysis_height_step_size = 0.10 char_analysis_height_num_steps = 5 - segmentation_min_box_width_px = 8 segmentation_min_charheight_percent = 0.5; segmentation_max_segment_width_percent_vs_average = 2.0; diff --git a/src/main.cpp b/src/main.cpp index e8a3505..c51cc32 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,90 +17,83 @@ * along with this program. If not, see . */ +#include +#include +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/imgproc/imgproc.hpp" - #include - #include +#include "tclap/CmdLine.h" +#include "support/filesystem.h" +#include "support/timing.h" +#include "alpr.h" - #include "opencv2/highgui/highgui.hpp" - #include "opencv2/imgproc/imgproc.hpp" +const std::string MAIN_WINDOW_NAME = "ALPR main window"; +const bool SAVE_LAST_VIDEO_STILL = false; +const std::string LAST_VIDEO_STILL_LOCATION = "/tmp/laststill.jpg"; - #include "tclap/CmdLine.h" - #include "support/filesystem.h" - #include "support/timing.h" - #include "alpr.h" +/** Function Headers */ +bool detectandshow(Alpr* alpr, cv::Mat frame, std::string region, bool writeJson); +bool measureProcessingTime = false; +int main( int argc, const char** argv ) +{ + std::string filename; + std::string runtimePath = ""; + bool outputJson = false; + int seektoms = 0; + bool detectRegion = false; + std::string templateRegion; + std::string country; + int topn; - const std::string MAIN_WINDOW_NAME = "ALPR main window"; + try + { + TCLAP::CmdLine cmd("OpenAlpr Command Line Utility", ' ', OPENALPR_VERSION); - const bool SAVE_LAST_VIDEO_STILL = false; - const std::string LAST_VIDEO_STILL_LOCATION = "/tmp/laststill.jpg"; + TCLAP::UnlabeledValueArg fileArg( "image_file", "Image containing license plates", true, "", "image_file_path" ); + TCLAP::ValueArg countryCodeArg("c","country","Country code to identify (either us for USA or eu for Europe). Default=us",false, "us" ,"country_code"); + TCLAP::ValueArg seekToMsArg("","seek","Seek to the specied millisecond in a video file. Default=0",false, 0 ,"integer_ms"); + TCLAP::ValueArg runtimeDirArg("r","runtime_dir","Path to the OpenAlpr runtime data directory",false, "" ,"runtime_dir"); + TCLAP::ValueArg templateRegionArg("t","template_region","Attempt to match the plate number against a region template (e.g., md for Maryland, ca for California)",false, "" ,"region code"); + TCLAP::ValueArg topNArg("n","topn","Max number of possible plate numbers to return. Default=10",false, 10 ,"topN"); - /** Function Headers */ - bool detectandshow(Alpr* alpr, cv::Mat frame, std::string region, bool writeJson); + TCLAP::SwitchArg jsonSwitch("j","json","Output recognition results in JSON format. Default=off", cmd, false); + TCLAP::SwitchArg detectRegionSwitch("d","detect_region","Attempt to detect the region of the plate image. Default=off", cmd, false); + TCLAP::SwitchArg clockSwitch("","clock","Measure/print the total time to process image and all plates. Default=off", cmd, false); + cmd.add( fileArg ); + cmd.add( countryCodeArg ); + cmd.add( seekToMsArg ); + cmd.add( topNArg ); + cmd.add( runtimeDirArg ); + cmd.add( templateRegionArg ); - bool measureProcessingTime = false; + cmd.parse( argc, argv ); - int main( int argc, const char** argv ) - { - std::string filename; - std::string runtimePath = ""; - bool outputJson = false; - int seektoms = 0; - bool detectRegion = false; - std::string templateRegion; - std::string country; - int topn; + filename = fileArg.getValue(); - try { + country = countryCodeArg.getValue(); + seektoms = seekToMsArg.getValue(); + outputJson = jsonSwitch.getValue(); + runtimePath = runtimeDirArg.getValue(); + detectRegion = detectRegionSwitch.getValue(); + templateRegion = templateRegionArg.getValue(); + topn = topNArg.getValue(); + measureProcessingTime = clockSwitch.getValue(); - TCLAP::CmdLine cmd("OpenAlpr Command Line Utility", ' ', OPENALPR_VERSION); - - TCLAP::UnlabeledValueArg fileArg( "image_file", "Image containing license plates", true, "", "image_file_path" ); - - TCLAP::ValueArg countryCodeArg("c","country","Country code to identify (either us for USA or eu for Europe). Default=us",false, "us" ,"country_code"); - TCLAP::ValueArg seekToMsArg("","seek","Seek to the specied millisecond in a video file. Default=0",false, 0 ,"integer_ms"); - TCLAP::ValueArg runtimeDirArg("r","runtime_dir","Path to the OpenAlpr runtime data directory",false, "" ,"runtime_dir"); - TCLAP::ValueArg templateRegionArg("t","template_region","Attempt to match the plate number against a region template (e.g., md for Maryland, ca for California)",false, "" ,"region code"); - TCLAP::ValueArg topNArg("n","topn","Max number of possible plate numbers to return. Default=10",false, 10 ,"topN"); - - TCLAP::SwitchArg jsonSwitch("j","json","Output recognition results in JSON format. Default=off", cmd, false); - TCLAP::SwitchArg detectRegionSwitch("d","detect_region","Attempt to detect the region of the plate image. Default=off", cmd, false); - TCLAP::SwitchArg clockSwitch("","clock","Measure/print the total time to process image and all plates. Default=off", cmd, false); - - cmd.add( fileArg ); - cmd.add( countryCodeArg ); - cmd.add( seekToMsArg ); - cmd.add( topNArg ); - cmd.add( runtimeDirArg ); - cmd.add( templateRegionArg ); - - cmd.parse( argc, argv ); - - filename = fileArg.getValue(); - - country = countryCodeArg.getValue(); - seektoms = seekToMsArg.getValue(); - outputJson = jsonSwitch.getValue(); - runtimePath = runtimeDirArg.getValue(); - detectRegion = detectRegionSwitch.getValue(); - templateRegion = templateRegionArg.getValue(); - topn = topNArg.getValue(); - measureProcessingTime = clockSwitch.getValue(); - - } catch (TCLAP::ArgException &e) // catch any exceptions - { - std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; - return 1; - } - - cv::Mat frame; + } + catch (TCLAP::ArgException &e) // catch any exceptions + { + std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; + return 1; + } + cv::Mat frame; Alpr alpr(country, runtimePath); alpr.setTopN(topn); @@ -125,15 +118,15 @@ cv::VideoCapture cap(0); if (!cap.isOpened()) { - std::cout << "Error opening webcam" << std::endl; - return 1; + std::cout << "Error opening webcam" << std::endl; + return 1; } while (cap.read(frame) == true) { - detectandshow(&alpr, frame, "", outputJson); - cv::waitKey(1); - framenum++; + detectandshow(&alpr, frame, "", outputJson); + cv::waitKey(1); + framenum++; } } else if (hasEnding(filename, ".avi") || hasEnding(filename, ".mp4") || hasEnding(filename, ".webm") || hasEnding(filename, ".flv")) @@ -148,16 +141,16 @@ while (cap.read(frame) == true) { - if (SAVE_LAST_VIDEO_STILL == true) - { - cv::imwrite(LAST_VIDEO_STILL_LOCATION, frame); - } - std::cout << "Frame: " << framenum << std::endl; + if (SAVE_LAST_VIDEO_STILL == true) + { + cv::imwrite(LAST_VIDEO_STILL_LOCATION, frame); + } + std::cout << "Frame: " << framenum << std::endl; - detectandshow( &alpr, frame, "", outputJson); - //create a 1ms delay - cv::waitKey(1); - framenum++; + detectandshow( &alpr, frame, "", outputJson); + //create a 1ms delay + cv::waitKey(1); + framenum++; } } else @@ -179,32 +172,31 @@ std::cerr << "Image file not found: " << filename << std::endl; } - } else if (DirectoryExists(filename.c_str())) { - std::vector files = getFilesInDir(filename.c_str()); + std::vector files = getFilesInDir(filename.c_str()); - std::sort( files.begin(), files.end(), stringCompare ); + std::sort( files.begin(), files.end(), stringCompare ); - for (int i = 0; i< files.size(); i++) + for (int i = 0; i< files.size(); i++) + { + if (hasEnding(files[i], ".jpg") || hasEnding(files[i], ".png")) { - if (hasEnding(files[i], ".jpg") || hasEnding(files[i], ".png")) - { - std::string fullpath = filename + "/" + files[i]; - std::cout << fullpath << std::endl; - frame = cv::imread( fullpath.c_str() ); - if (detectandshow( &alpr, frame, "", outputJson)) - { - //while ((char) cv::waitKey(50) != 'c') { } - } - else - { - //cv::waitKey(50); - } - } - + std::string fullpath = filename + "/" + files[i]; + std::cout << fullpath << std::endl; + frame = cv::imread( fullpath.c_str() ); + if (detectandshow( &alpr, frame, "", outputJson)) + { + //while ((char) cv::waitKey(50) != 'c') { } + } + else + { + //cv::waitKey(50); + } } + + } } else { @@ -212,53 +204,45 @@ return 1; } - - return 0; - } +} +bool detectandshow( Alpr* alpr, cv::Mat frame, std::string region, bool writeJson) +{ - bool detectandshow( Alpr* alpr, cv::Mat frame, std::string region, bool writeJson) - { + std::vector buffer; + cv::imencode(".bmp", frame, buffer ); + timespec startTime; + getTime(&startTime); - std::vector buffer; - cv::imencode(".bmp", frame, buffer ); + std::vector results = alpr->recognize(buffer); - - timespec startTime; - getTime(&startTime); - - - std::vector results = alpr->recognize(buffer); - - - if (writeJson) - { + if (writeJson) + { std::cout << alpr->toJson(results) << std::endl; - } - else - { + } + else + { for (int i = 0; i < results.size(); i++) { std::cout << "plate" << i << ": " << results[i].result_count << " results -- Processing Time = " << results[i].processing_time_ms << "ms." << std::endl; for (int k = 0; k < results[i].topNPlates.size(); k++) { - std::cout << " - " << results[i].topNPlates[k].characters << "\t confidence: " << results[i].topNPlates[k].overall_confidence << "\t template_match: " << results[i].topNPlates[k].matches_template << std::endl; + std::cout << " - " << results[i].topNPlates[k].characters << "\t confidence: " << results[i].topNPlates[k].overall_confidence << "\t template_match: " << results[i].topNPlates[k].matches_template << std::endl; } } - } + } - timespec endTime; - getTime(&endTime); - if (measureProcessingTime) - std::cout << "Total Time to process image: " << diffclock(startTime, endTime) << "ms." << std::endl; + timespec endTime; + getTime(&endTime); + if (measureProcessingTime) + std::cout << "Total Time to process image: " << diffclock(startTime, endTime) << "ms." << std::endl; + if (results.size() > 0) + return true; + return false; - if (results.size() > 0) - return true; - return false; - - } +} diff --git a/src/misc_utilities/benchmark.cpp b/src/misc_utilities/benchmark.cpp index 909775b..bcfe1b9 100644 --- a/src/misc_utilities/benchmark.cpp +++ b/src/misc_utilities/benchmark.cpp @@ -17,12 +17,12 @@ * along with this program. If not, see . */ - #include "opencv2/highgui/highgui.hpp" - #include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/imgproc/imgproc.hpp" - #include - #include - #include +#include +#include +#include #include #include // std::accumulate @@ -34,8 +34,8 @@ //#include "utility.h" #include "support/filesystem.h" - using namespace std; - using namespace cv; +using namespace std; +using namespace cv; // Given a directory full of lp images (named [statecode]#.png) crop out the alphanumeric characters. // These will be used to train the OCR @@ -44,47 +44,44 @@ void outputStats(vector datapoints); int main( int argc, const char** argv ) { - string country; - string benchmarkName; - string inDir; - string outDir; - Mat frame; - + string country; + string benchmarkName; + string inDir; + string outDir; + Mat frame; //Check if user specify image to process if(argc == 5) { - country = argv[1]; - benchmarkName = argv[2]; - inDir = argv[3]; - outDir = argv[4]; + country = argv[1]; + benchmarkName = argv[2]; + inDir = argv[3]; + outDir = argv[4]; - - }else{ - printf("Use:\n\t%s [country] [benchmark name] [img input dir] [results output dir]\n",argv[0]); - printf("\tex: %s us speed ./speed/usimages ./speed\n",argv[0]); - printf("\n"); - printf("\ttest names are: speed, segocr, detection\n\n" ); - return 0; } - + else + { + printf("Use:\n\t%s [country] [benchmark name] [img input dir] [results output dir]\n",argv[0]); + printf("\tex: %s us speed ./speed/usimages ./speed\n",argv[0]); + printf("\n"); + printf("\ttest names are: speed, segocr, detection\n\n" ); + return 0; + } if (DirectoryExists(inDir.c_str()) == false) { - printf("Input dir does not exist\n"); - return 0; + printf("Input dir does not exist\n"); + return 0; } if (DirectoryExists(outDir.c_str()) == false) { - printf("Output dir does not exist\n"); - return 0; + printf("Output dir does not exist\n"); + return 0; } - vector files = getFilesInDir(inDir.c_str()); sort( files.begin(), files.end(), stringCompare ); - if (benchmarkName.compare("segocr") == 0) { Config* config = new Config(country); @@ -92,55 +89,50 @@ int main( int argc, const char** argv ) OCR* ocr = new OCR(config); - for (int i = 0; i< files.size(); i++) { if (hasEnding(files[i], ".png")) { - string fullpath = inDir + "/" + files[i]; + string fullpath = inDir + "/" + files[i]; - frame = imread( fullpath.c_str() ); - resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx)); + frame = imread( fullpath.c_str() ); + resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx)); - Rect plateCoords; - plateCoords.x = 0; - plateCoords.y = 0; - plateCoords.width = frame.cols; - plateCoords.height = frame.rows; + Rect plateCoords; + plateCoords.x = 0; + plateCoords.y = 0; + plateCoords.width = frame.cols; + plateCoords.height = frame.rows; - char statecode[3]; - statecode[0] = files[i][0]; - statecode[1] = files[i][1]; - statecode[2] = '\0'; - string statecodestr(statecode); + char statecode[3]; + statecode[0] = files[i][0]; + statecode[1] = files[i][1]; + statecode[2] = '\0'; + string statecodestr(statecode); - CharacterRegion charRegion(frame, config); + CharacterRegion charRegion(frame, config); - if (abs(charRegion.getTopLine().angle) > 4) - { - // Rotate image: - Mat rotated(frame.size(), frame.type()); - Mat rot_mat( 2, 3, CV_32FC1 ); - Point center = Point( frame.cols/2, frame.rows/2 ); + if (abs(charRegion.getTopLine().angle) > 4) + { + // Rotate image: + Mat rotated(frame.size(), frame.type()); + Mat rot_mat( 2, 3, CV_32FC1 ); + Point center = Point( frame.cols/2, frame.rows/2 ); - rot_mat = getRotationMatrix2D( center, charRegion.getTopLine().angle, 1.0 ); - warpAffine( frame, rotated, rot_mat, frame.size() ); + rot_mat = getRotationMatrix2D( center, charRegion.getTopLine().angle, 1.0 ); + warpAffine( frame, rotated, rot_mat, frame.size() ); - rotated.copyTo(frame); - } + rotated.copyTo(frame); + } + CharacterSegmenter charSegmenter(frame, charRegion.thresholdsInverted(), config); + ocr->performOCR(charSegmenter.getThresholds(), charSegmenter.characters); + ocr->postProcessor->analyze(statecode, 25); + cout << files[i] << "," << statecode << "," << ocr->postProcessor->bestChars << endl; - CharacterSegmenter charSegmenter(frame, charRegion.thresholdsInverted(), config); - ocr->performOCR(charSegmenter.getThresholds(), charSegmenter.characters); - ocr->postProcessor->analyze(statecode, 25); - - cout << files[i] << "," << statecode << "," << ocr->postProcessor->bestChars << endl; - - - imshow("Current LP", frame); - waitKey(5); - + imshow("Current LP", frame); + waitKey(5); } @@ -158,14 +150,13 @@ int main( int argc, const char** argv ) { if (hasEnding(files[i], ".png")) { - string fullpath = inDir + "/" + files[i]; - frame = imread( fullpath.c_str() ); + string fullpath = inDir + "/" + files[i]; + frame = imread( fullpath.c_str() ); - vector regions = plateDetector.detect(frame); - - imshow("Current LP", frame); - waitKey(5); + vector regions = plateDetector.detect(frame); + imshow("Current LP", frame); + waitKey(5); } @@ -173,7 +164,7 @@ int main( int argc, const char** argv ) } else if (benchmarkName.compare("speed") == 0) { - // Benchmarks speed of region detection, plate analysis, and OCR + // Benchmarks speed of region detection, plate analysis, and OCR timespec startTime; timespec endTime; @@ -197,75 +188,72 @@ int main( int argc, const char** argv ) vector ocrTimes; vector postProcessTimes; - for (int i = 0; i< files.size(); i++) { if (hasEnding(files[i], ".png")) { - cout << "Image: " << files[i] << endl; + cout << "Image: " << files[i] << endl; - string fullpath = inDir + "/" + files[i]; - frame = imread( fullpath.c_str() ); + string fullpath = inDir + "/" + files[i]; + frame = imread( fullpath.c_str() ); + getTime(&startTime); + alpr.recognize(frame); + getTime(&endTime); + double endToEndTime = diffclock(startTime, endTime); + cout << " -- End to End recognition time: " << endToEndTime << "ms." << endl; + endToEndTimes.push_back(endToEndTime); - getTime(&startTime); - alpr.recognize(frame); - getTime(&endTime); - double endToEndTime = diffclock(startTime, endTime); - cout << " -- End to End recognition time: " << endToEndTime << "ms." << endl; - endToEndTimes.push_back(endToEndTime); + getTime(&startTime); + vector regions = plateDetector.detect(frame); + getTime(&endTime); - getTime(&startTime); - vector regions = plateDetector.detect(frame); - getTime(&endTime); + double regionDetectionTime = diffclock(startTime, endTime); + cout << " -- Region detection time: " << regionDetectionTime << "ms." << endl; + regionDetectionTimes.push_back(regionDetectionTime); - double regionDetectionTime = diffclock(startTime, endTime); - cout << " -- Region detection time: " << regionDetectionTime << "ms." << endl; - regionDetectionTimes.push_back(regionDetectionTime); + for (int z = 0; z < regions.size(); z++) + { + getTime(&startTime); + char temp[5]; + stateIdentifier.recognize(frame, regions[z], temp); + getTime(&endTime); + double stateidTime = diffclock(startTime, endTime); + cout << "\tRegion " << z << ": State ID time: " << stateidTime << "ms." << endl; + stateIdTimes.push_back(stateidTime); - for (int z = 0; z < regions.size(); z++) - { - getTime(&startTime); - char temp[5]; - stateIdentifier.recognize(frame, regions[z], temp); - getTime(&endTime); - double stateidTime = diffclock(startTime, endTime); - cout << "\tRegion " << z << ": State ID time: " << stateidTime << "ms." << endl; - stateIdTimes.push_back(stateidTime); + getTime(&startTime); + LicensePlateCandidate lp(frame, regions[z], &config); + lp.recognize(); + getTime(&endTime); + double analysisTime = diffclock(startTime, endTime); + cout << "\tRegion " << z << ": Analysis time: " << analysisTime << "ms." << endl; - getTime(&startTime); - LicensePlateCandidate lp(frame, regions[z], &config); - lp.recognize(); - getTime(&endTime); - double analysisTime = diffclock(startTime, endTime); - cout << "\tRegion " << z << ": Analysis time: " << analysisTime << "ms." << endl; + if (lp.confidence > 10) + { + lpAnalysisPositiveTimes.push_back(analysisTime); - if (lp.confidence > 10) - { - lpAnalysisPositiveTimes.push_back(analysisTime); + getTime(&startTime); + ocr.performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters); + getTime(&endTime); + double ocrTime = diffclock(startTime, endTime); + cout << "\tRegion " << z << ": OCR time: " << ocrTime << "ms." << endl; + ocrTimes.push_back(ocrTime); + getTime(&startTime); + ocr.postProcessor->analyze("", 25); + getTime(&endTime); + double postProcessTime = diffclock(startTime, endTime); + cout << "\tRegion " << z << ": PostProcess time: " << postProcessTime << "ms." << endl; + postProcessTimes.push_back(postProcessTime); + } + else + { + lpAnalysisNegativeTimes.push_back(analysisTime); + } + } - getTime(&startTime); - ocr.performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters); - getTime(&endTime); - double ocrTime = diffclock(startTime, endTime); - cout << "\tRegion " << z << ": OCR time: " << ocrTime << "ms." << endl; - ocrTimes.push_back(ocrTime); - - getTime(&startTime); - ocr.postProcessor->analyze("", 25); - getTime(&endTime); - double postProcessTime = diffclock(startTime, endTime); - cout << "\tRegion " << z << ": PostProcess time: " << postProcessTime << "ms." << endl; - postProcessTimes.push_back(postProcessTime); - } - else - { - lpAnalysisNegativeTimes.push_back(analysisTime); - } - } - - waitKey(5); + waitKey(5); } @@ -273,7 +261,6 @@ int main( int argc, const char** argv ) cout << endl << "---------------------" << endl; - cout << "End to End Time Statistics:" << endl; outputStats(endToEndTimes); cout << endl; @@ -315,24 +302,23 @@ int main( int argc, const char** argv ) { if (hasEnding(files[i], ".png")) { - string fullpath = inDir + "/" + files[i]; - frame = imread( fullpath.c_str() ); + string fullpath = inDir + "/" + files[i]; + frame = imread( fullpath.c_str() ); - vector buffer; - imencode(".bmp", frame, buffer ); + vector buffer; + imencode(".bmp", frame, buffer ); - vector results = alpr.recognize(buffer); + vector results = alpr.recognize(buffer); - outputdatafile << files[i] << ": "; - for (int z = 0; z < results.size(); z++) - { - outputdatafile << results[z].bestPlate.characters << ", "; - } - outputdatafile << endl; - - imshow("Current LP", frame); - waitKey(5); + outputdatafile << files[i] << ": "; + for (int z = 0; z < results.size(); z++) + { + outputdatafile << results[z].bestPlate.characters << ", "; + } + outputdatafile << endl; + imshow("Current LP", frame); + waitKey(5); } @@ -350,7 +336,7 @@ void outputStats(vector datapoints) std::vector diff(datapoints.size()); std::transform(datapoints.begin(), datapoints.end(), diff.begin(), - std::bind2nd(std::minus(), mean)); + std::bind2nd(std::minus(), mean)); double sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0); double stdev = std::sqrt(sq_sum / datapoints.size()); diff --git a/src/misc_utilities/classifychars.cpp b/src/misc_utilities/classifychars.cpp index 47c200b..c8f2463 100644 --- a/src/misc_utilities/classifychars.cpp +++ b/src/misc_utilities/classifychars.cpp @@ -31,8 +31,8 @@ #include "support/filesystem.h" #include "ocr.h" - using namespace std; - using namespace cv; +using namespace std; +using namespace cv; // Given a directory full of lp images (named [statecode]#.png) crop out the alphanumeric characters. // These will be used to train the OCR @@ -61,36 +61,34 @@ const int DASHBOARD_COLUMNS = 3; #endif - void showDashboard(vector images, vector selectedImages, int selectedIndex); vector showCharSelection(Mat image, vector charRegions, string state); int main( int argc, const char** argv ) { - string inDir; - string outDir; - Mat frame; - + string inDir; + string outDir; + Mat frame; //Check if user specify image to process if(argc == 3) { - inDir = argv[1]; - outDir = argv[2]; + inDir = argv[1]; + outDir = argv[2]; - - }else{ - printf("Use:\n\t%s indirectory outdirectory\n",argv[0]); - printf("Ex: \n\t%s ./pics/ ./out \n",argv[0]); - return 0; } - + else + { + printf("Use:\n\t%s indirectory outdirectory\n",argv[0]); + printf("Ex: \n\t%s ./pics/ ./out \n",argv[0]); + return 0; + } if (DirectoryExists(outDir.c_str()) == false) { - printf("Output dir does not exist\n"); - return 0; + printf("Output dir does not exist\n"); + return 0; } cout << "Usage: " << endl; @@ -110,172 +108,166 @@ int main( int argc, const char** argv ) if (DirectoryExists(inDir.c_str())) { - vector files = getFilesInDir(inDir.c_str()); + vector files = getFilesInDir(inDir.c_str()); - sort( files.begin(), files.end(), stringCompare ); + sort( files.begin(), files.end(), stringCompare ); - for (int i = 0; i< files.size(); i++) + for (int i = 0; i< files.size(); i++) + { + if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg")) { - if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg")) - { - string fullpath = inDir + "/" + files[i]; - cout << fullpath << endl; - frame = imread( fullpath.c_str() ); - resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx)); + string fullpath = inDir + "/" + files[i]; + cout << fullpath << endl; + frame = imread( fullpath.c_str() ); + resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx)); - imshow ("Original", frame); + imshow ("Original", frame); + char statecode[3]; + statecode[0] = files[i][0]; + statecode[1] = files[i][1]; + statecode[2] = '\0'; + string statecodestr(statecode); - char statecode[3]; - statecode[0] = files[i][0]; - statecode[1] = files[i][1]; - statecode[2] = '\0'; - string statecodestr(statecode); + CharacterRegion regionizer(frame, config); - CharacterRegion regionizer(frame, config); + if (abs(regionizer.getTopLine().angle) > 4) + { + // Rotate image: + Mat rotated(frame.size(), frame.type()); + Mat rot_mat( 2, 3, CV_32FC1 ); + Point center = Point( frame.cols/2, frame.rows/2 ); - if (abs(regionizer.getTopLine().angle) > 4) - { - // Rotate image: - Mat rotated(frame.size(), frame.type()); - Mat rot_mat( 2, 3, CV_32FC1 ); - Point center = Point( frame.cols/2, frame.rows/2 ); + rot_mat = getRotationMatrix2D( center, regionizer.getTopLine().angle, 1.0 ); + warpAffine( frame, rotated, rot_mat, frame.size() ); - rot_mat = getRotationMatrix2D( center, regionizer.getTopLine().angle, 1.0 ); - warpAffine( frame, rotated, rot_mat, frame.size() ); + rotated.copyTo(frame); + } - rotated.copyTo(frame); - } + CharacterSegmenter charSegmenter(frame, regionizer.thresholdsInverted(), config); - CharacterSegmenter charSegmenter(frame, regionizer.thresholdsInverted(), config); + //ocr.cleanCharRegions(charSegmenter.thresholds, charSegmenter.characters); - //ocr.cleanCharRegions(charSegmenter.thresholds, charSegmenter.characters); + ocr.performOCR(charSegmenter.getThresholds(), charSegmenter.characters); + ocr.postProcessor->analyze(statecodestr, 25); + cout << "OCR results: " << ocr.postProcessor->bestChars << endl; - ocr.performOCR(charSegmenter.getThresholds(), charSegmenter.characters); - ocr.postProcessor->analyze(statecodestr, 25); - cout << "OCR results: " << ocr.postProcessor->bestChars << endl; + vector selectedBoxes(charSegmenter.getThresholds().size()); + for (int z = 0; z < charSegmenter.getThresholds().size(); z++) + selectedBoxes[z] = false; + int curDashboardSelection = 0; - vector selectedBoxes(charSegmenter.getThresholds().size()); - for (int z = 0; z < charSegmenter.getThresholds().size(); z++) - selectedBoxes[z] = false; + vector humanInputs(charSegmenter.characters.size()); - int curDashboardSelection = 0; + for (int z = 0; z < charSegmenter.characters.size(); z++) + humanInputs[z] = ' '; - vector humanInputs(charSegmenter.characters.size()); + showDashboard(charSegmenter.getThresholds(), selectedBoxes, 0); - for (int z = 0; z < charSegmenter.characters.size(); z++) - humanInputs[z] = ' '; + char waitkey = (char) waitKey(50); - showDashboard(charSegmenter.getThresholds(), selectedBoxes, 0); + while (waitkey != 'n' && waitkey != 'p') // Next image + { + if (waitkey == LEFT_ARROW_KEY) // left arrow key + { + if (curDashboardSelection > 0) + curDashboardSelection--; + showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection); + } + else if (waitkey == RIGHT_ARROW_KEY) // right arrow key + { + if (curDashboardSelection < charSegmenter.getThresholds().size() - 1) + curDashboardSelection++; + showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection); + } + else if (waitkey == DOWN_ARROW_KEY) + { + if (curDashboardSelection + DASHBOARD_COLUMNS <= charSegmenter.getThresholds().size() - 1) + curDashboardSelection += DASHBOARD_COLUMNS; + showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection); + } + else if (waitkey == UP_ARROW_KEY) + { + if (curDashboardSelection - DASHBOARD_COLUMNS >= 0) + curDashboardSelection -= DASHBOARD_COLUMNS; + showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection); + } + else if (waitkey == ENTER_KEY) + { + vector tempdata = showCharSelection(charSegmenter.getThresholds()[curDashboardSelection], charSegmenter.characters, statecodestr); + for (int c = 0; c < charSegmenter.characters.size(); c++) + humanInputs[c] = tempdata[c]; + } + else if (waitkey == SPACE_KEY) + { + selectedBoxes[curDashboardSelection] = !selectedBoxes[curDashboardSelection]; + showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection); + } + else if (waitkey == 's' || waitkey == 'S') + { + bool somethingSelected = false; + bool chardataTagged = false; + for (int c = 0; c < charSegmenter.getThresholds().size(); c++) + { + if (selectedBoxes[c]) + { + somethingSelected = true; + break; + } + } + for (int c = 0; c < charSegmenter.characters.size(); c++) + { + if (humanInputs[c] != ' ') + { + chardataTagged = true; + break; + } + } + // Save + if (somethingSelected && chardataTagged) + { + for (int c = 0; c < charSegmenter.characters.size(); c++) + { + if (humanInputs[c] == ' ') + continue; + for (int t = 0; t < charSegmenter.getThresholds().size(); t++) + { + if (selectedBoxes[t] == false) + continue; - char waitkey = (char) waitKey(50); + stringstream filename; + Mat cropped = charSegmenter.getThresholds()[t](charSegmenter.characters[c]); + filename << outDir << "/" << humanInputs[c] << "-" << t << "-" << files[i]; + imwrite(filename.str(), cropped); + cout << "Writing char image: " << filename.str() << endl; + } + } + } + else if (somethingSelected == false) + cout << "Did not select any boxes" << endl; + else if (chardataTagged == false) + cout << "You have not tagged any characters" << endl; + } - while (waitkey != 'n' && waitkey != 'p') // Next image - { - if (waitkey == LEFT_ARROW_KEY) // left arrow key - { - if (curDashboardSelection > 0) - curDashboardSelection--; - showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection); - } - else if (waitkey == RIGHT_ARROW_KEY) // right arrow key - { - if (curDashboardSelection < charSegmenter.getThresholds().size() - 1) - curDashboardSelection++; - showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection); - } - else if (waitkey == DOWN_ARROW_KEY) - { - if (curDashboardSelection + DASHBOARD_COLUMNS <= charSegmenter.getThresholds().size() - 1) - curDashboardSelection += DASHBOARD_COLUMNS; - showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection); - } - else if (waitkey == UP_ARROW_KEY) - { - if (curDashboardSelection - DASHBOARD_COLUMNS >= 0) - curDashboardSelection -= DASHBOARD_COLUMNS; - showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection); - } - else if (waitkey == ENTER_KEY) - { - vector tempdata = showCharSelection(charSegmenter.getThresholds()[curDashboardSelection], charSegmenter.characters, statecodestr); - for (int c = 0; c < charSegmenter.characters.size(); c++) - humanInputs[c] = tempdata[c]; - } - else if (waitkey == SPACE_KEY) - { - selectedBoxes[curDashboardSelection] = !selectedBoxes[curDashboardSelection]; - showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection); - } - else if (waitkey == 's' || waitkey == 'S') - { - bool somethingSelected = false; - bool chardataTagged = false; - for (int c = 0; c < charSegmenter.getThresholds().size(); c++) - { - if (selectedBoxes[c]) - { - somethingSelected = true; - break; - } - } - for (int c = 0; c < charSegmenter.characters.size(); c++) - { - if (humanInputs[c] != ' ') - { - chardataTagged = true; - break; - } - } - // Save - if (somethingSelected && chardataTagged) - { + waitkey = (char) waitKey(50); - for (int c = 0; c < charSegmenter.characters.size(); c++) - { - if (humanInputs[c] == ' ') - continue; + } - for (int t = 0; t < charSegmenter.getThresholds().size(); t++) - { - if (selectedBoxes[t] == false) - continue; - - stringstream filename; - Mat cropped = charSegmenter.getThresholds()[t](charSegmenter.characters[c]); - filename << outDir << "/" << humanInputs[c] << "-" << t << "-" << files[i]; - imwrite(filename.str(), cropped); - cout << "Writing char image: " << filename.str() << endl; - } - } - } - else if (somethingSelected == false) - cout << "Did not select any boxes" << endl; - else if (chardataTagged == false) - cout << "You have not tagged any characters" << endl; - } - - waitkey = (char) waitKey(50); - - } - - if (waitkey == 'p') - i = i - 2; - if (i < -1) - i = -1; - - - } + if (waitkey == 'p') + i = i - 2; + if (i < -1) + i = -1; } + + } } } - void showDashboard(vector images, vector selectedImages, int selectedIndex) { vector vecCopy; @@ -309,62 +301,60 @@ void showDashboard(vector images, vector selectedImages, int selected vector showCharSelection(Mat image, vector charRegions, string state) { - int curCharIdx = 0; + int curCharIdx = 0; - vector humanInputs(charRegions.size()); - for (int i = 0; i < charRegions.size(); i++) - humanInputs[i] = (char) SPACE_KEY; + vector humanInputs(charRegions.size()); + for (int i = 0; i < charRegions.size(); i++) + humanInputs[i] = (char) SPACE_KEY; + char waitkey = (char) waitKey(50); + while (waitkey != ENTER_KEY && waitkey != ESCAPE_KEY) + { + Mat imgCopy(image.size(), image.type()); + image.copyTo(imgCopy); + cvtColor(imgCopy, imgCopy, CV_GRAY2BGR); - char waitkey = (char) waitKey(50); - while (waitkey != ENTER_KEY && waitkey != ESCAPE_KEY) + rectangle(imgCopy, charRegions[curCharIdx], Scalar(0, 255, 0), 1); + + imshow("Character selector", imgCopy); + + if (waitkey == LEFT_ARROW_KEY) + curCharIdx--; + else if (waitkey == RIGHT_ARROW_KEY ) + curCharIdx++; + else if ((waitkey >= '0' && waitkey <= '9') || (waitkey >= 'a' && waitkey <= 'z') || waitkey == SPACE_KEY) { - Mat imgCopy(image.size(), image.type()); - image.copyTo(imgCopy); - cvtColor(imgCopy, imgCopy, CV_GRAY2BGR); + // Save the character to disk + humanInputs[curCharIdx] = toupper((char) waitkey); + curCharIdx++; - rectangle(imgCopy, charRegions[curCharIdx], Scalar(0, 255, 0), 1); - - imshow("Character selector", imgCopy); - - if (waitkey == LEFT_ARROW_KEY) - curCharIdx--; - else if (waitkey == RIGHT_ARROW_KEY ) - curCharIdx++; - else if ((waitkey >= '0' && waitkey <= '9') || (waitkey >= 'a' && waitkey <= 'z') || waitkey == SPACE_KEY) - { - // Save the character to disk - humanInputs[curCharIdx] = toupper((char) waitkey); - curCharIdx++; - - if (curCharIdx >= charRegions.size()) - { - waitkey = (char) ENTER_KEY; - break; - } - } - - if (curCharIdx < 0) - curCharIdx = 0; if (curCharIdx >= charRegions.size()) - curCharIdx = charRegions.size() -1; - - waitkey = (char) waitKey(50); + { + waitkey = (char) ENTER_KEY; + break; + } } - if (waitkey == ENTER_KEY) + if (curCharIdx < 0) + curCharIdx = 0; + if (curCharIdx >= charRegions.size()) + curCharIdx = charRegions.size() -1; + + waitkey = (char) waitKey(50); + } + + if (waitkey == ENTER_KEY) + { + // Save all the inputs + for (int i = 0; i < charRegions.size(); i++) { - // Save all the inputs - for (int i = 0; i < charRegions.size(); i++) - { - if (humanInputs[i] != (char) SPACE_KEY) - cout << "Tagged " << state << " char code: '" << humanInputs[i] << "' at char position: " << i << endl; - } - + if (humanInputs[i] != (char) SPACE_KEY) + cout << "Tagged " << state << " char code: '" << humanInputs[i] << "' at char position: " << i << endl; } - destroyWindow("Character selector"); + } + destroyWindow("Character selector"); - return humanInputs; + return humanInputs; } diff --git a/src/misc_utilities/prepcharsfortraining.cpp b/src/misc_utilities/prepcharsfortraining.cpp index 6f51ce1..b49ac33 100644 --- a/src/misc_utilities/prepcharsfortraining.cpp +++ b/src/misc_utilities/prepcharsfortraining.cpp @@ -17,49 +17,46 @@ * along with this program. If not, see . */ - #include "opencv2/highgui/highgui.hpp" - #include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/imgproc/imgproc.hpp" - #include - #include +#include +#include #include #include #include "support/filesystem.h" - using namespace std; - using namespace cv; - - +using namespace std; +using namespace cv; // Takes a directory full of single char images, and plops them on a big tif files // Also creates a box file so Tesseract can recognize it int main( int argc, const char** argv ) { - string inDir; - + string inDir; //Check if user specify image to process if(argc == 2) { - inDir = argv[1]; + inDir = argv[1]; - }else{ - printf("Use:\n\t%s input dir \n",argv[0]); - return 0; } - + else + { + printf("Use:\n\t%s input dir \n",argv[0]); + return 0; + } if (DirectoryExists(inDir.c_str()) == false) { - printf("Output dir does not exist\n"); - return 0; + printf("Output dir does not exist\n"); + return 0; } cout << "Usage: " << endl; cout << "\tinputdir -- input dir for benchmark data" << endl; - if (DirectoryExists(inDir.c_str())) { const int X_OFFSET = 10; @@ -74,97 +71,92 @@ int main( int argc, const char** argv ) const int TILE_HEIGHT = 70; const int CHAR_VERT_OFFSET = 48; - vector files = getFilesInDir(inDir.c_str()); + vector files = getFilesInDir(inDir.c_str()); - sort( files.begin(), files.end(), stringCompare ); + sort( files.begin(), files.end(), stringCompare ); + int tiles_per_row = ((float) (HORIZONTAL_RESOLUTION - (PAGE_MARGIN_X * 2))) / ((float) TILE_WIDTH); + int lines = files.size() / (tiles_per_row); + int vertical_resolution = (lines * TILE_HEIGHT) + (PAGE_MARGIN_Y * 2) ; + cout << tiles_per_row << " : " << vertical_resolution << endl; - int tiles_per_row = ((float) (HORIZONTAL_RESOLUTION - (PAGE_MARGIN_X * 2))) / ((float) TILE_WIDTH); - int lines = files.size() / (tiles_per_row); - int vertical_resolution = (lines * TILE_HEIGHT) + (PAGE_MARGIN_Y * 2) ; - cout << tiles_per_row << " : " << vertical_resolution << endl; + Mat bigTif = Mat::zeros(Size(HORIZONTAL_RESOLUTION, vertical_resolution), CV_8U); + bitwise_not(bigTif, bigTif); - Mat bigTif = Mat::zeros(Size(HORIZONTAL_RESOLUTION, vertical_resolution), CV_8U); - bitwise_not(bigTif, bigTif); + stringstream boxFileOut; - stringstream boxFileOut; + for (int i = 0; i< files.size(); i++) + { + int col = i % tiles_per_row; + int line = i / tiles_per_row; - for (int i = 0; i< files.size(); i++) + int xPos = (col * TILE_WIDTH) + PAGE_MARGIN_X; + int yPos = (line * TILE_HEIGHT) + PAGE_MARGIN_Y; + + if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg")) { - int col = i % tiles_per_row; - int line = i / tiles_per_row; + string fullpath = inDir + "/" + files[i]; - int xPos = (col * TILE_WIDTH) + PAGE_MARGIN_X; - int yPos = (line * TILE_HEIGHT) + PAGE_MARGIN_Y; + cout << "Processing file: " << (i + 1) << " of " << files.size() << endl; - if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg")) - { - string fullpath = inDir + "/" + files[i]; + char charcode = files[i][0]; - cout << "Processing file: " << (i + 1) << " of " << files.size() << endl; + Mat characterImg = imread(fullpath); + Mat charImgCopy = Mat::zeros(Size(150, 150), characterImg.type()); + bitwise_not(charImgCopy, charImgCopy); - char charcode = files[i][0]; + characterImg.copyTo(charImgCopy(Rect(X_OFFSET, Y_OFFSET, characterImg.cols, characterImg.rows))); + cvtColor(charImgCopy, charImgCopy, CV_BGR2GRAY); + bitwise_not(charImgCopy, charImgCopy); - Mat characterImg = imread(fullpath); - Mat charImgCopy = Mat::zeros(Size(150, 150), characterImg.type()); - bitwise_not(charImgCopy, charImgCopy); + vector > contours; - characterImg.copyTo(charImgCopy(Rect(X_OFFSET, Y_OFFSET, characterImg.cols, characterImg.rows))); - cvtColor(charImgCopy, charImgCopy, CV_BGR2GRAY); - bitwise_not(charImgCopy, charImgCopy); + //imshow("copy", charImgCopy); + findContours(charImgCopy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); - vector > contours; + Rect tallestRect(0, 0, 0, 0); + for (int c = 0; c < contours.size(); c++) + { + Rect tmpRect = boundingRect(contours[c]); + if (tmpRect.height > tallestRect.height) + tallestRect = tmpRect; + } - //imshow("copy", charImgCopy); - findContours(charImgCopy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); + //cout << tallestRect.x << ":" << tallestRect.y << " -- " << tallestRect.width << ":" << tallestRect.height << endl; - Rect tallestRect(0, 0, 0, 0); - for (int c = 0; c < contours.size(); c++) - { - Rect tmpRect = boundingRect(contours[c]); - if (tmpRect.height > tallestRect.height) - tallestRect = tmpRect; - } + Rect cropRect(0, tallestRect.y - Y_OFFSET, tallestRect.width, tallestRect.height); - //cout << tallestRect.x << ":" << tallestRect.y << " -- " << tallestRect.width << ":" << tallestRect.height << endl; + //cout << "Cropped: " << cropRect.x << ":" << cropRect.y << " -- " << cropRect.width << ":" << cropRect.height << endl; + Mat cropped(characterImg, cropRect); + cvtColor(cropped, cropped, CV_BGR2GRAY); - Rect cropRect(0, tallestRect.y - Y_OFFSET, tallestRect.width, tallestRect.height); + Rect destinationRect(xPos + (CHAR_HORIZ_OFFSET - tallestRect.width), yPos + (CHAR_VERT_OFFSET - tallestRect.height), tallestRect.width, tallestRect.height); + //cout << "1" << endl; - //cout << "Cropped: " << cropRect.x << ":" << cropRect.y << " -- " << cropRect.width << ":" << cropRect.height << endl; - Mat cropped(characterImg, cropRect); - cvtColor(cropped, cropped, CV_BGR2GRAY); + cropped.copyTo(bigTif(destinationRect)); - Rect destinationRect(xPos + (CHAR_HORIZ_OFFSET - tallestRect.width), yPos + (CHAR_VERT_OFFSET - tallestRect.height), tallestRect.width, tallestRect.height); + int x1= destinationRect.x - 2; + int y1 = (vertical_resolution - destinationRect.y - destinationRect.height) - 2; + int x2 = (destinationRect.x + destinationRect.width) + 2; + int y2 = (vertical_resolution - destinationRect.y) + 2; + //0 70 5602 85 5636 0 + boxFileOut << charcode << " " << x1 << " " << y1 << " "; + boxFileOut << x2 << " " << y2 ; + boxFileOut << " 0" << endl; - //cout << "1" << endl; + //rectangle(characterImg, tallestRect, Scalar(0, 255, 0)); + //imshow("characterImg", cropped); - cropped.copyTo(bigTif(destinationRect)); - - - int x1= destinationRect.x - 2; - int y1 = (vertical_resolution - destinationRect.y - destinationRect.height) - 2; - int x2 = (destinationRect.x + destinationRect.width) + 2; - int y2 = (vertical_resolution - destinationRect.y) + 2; - //0 70 5602 85 5636 0 - boxFileOut << charcode << " " << x1 << " " << y1 << " "; - boxFileOut << x2 << " " << y2 ; - boxFileOut << " 0" << endl; - - //rectangle(characterImg, tallestRect, Scalar(0, 255, 0)); - //imshow("characterImg", cropped); - - waitKey(2); - - - } + waitKey(2); } + } - imwrite("combined.tif", bigTif); - ofstream boxFile("combined.box", std::ios::out); - boxFile << boxFileOut.str(); + imwrite("combined.tif", bigTif); + ofstream boxFile("combined.box", std::ios::out); + boxFile << boxFileOut.str(); } diff --git a/src/misc_utilities/sortstate.cpp b/src/misc_utilities/sortstate.cpp index d43fbe9..36449dd 100644 --- a/src/misc_utilities/sortstate.cpp +++ b/src/misc_utilities/sortstate.cpp @@ -17,11 +17,11 @@ * along with this program. If not, see . */ - #include "opencv2/highgui/highgui.hpp" - #include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/imgproc/imgproc.hpp" - #include - #include +#include +#include #include #include "regiondetector.h" @@ -30,34 +30,34 @@ #include "utility.h" #include "support/filesystem.h" - using namespace std; - using namespace cv; +using namespace std; +using namespace cv; // Given a directory full of pre-cropped images, identify the state that each image belongs to. // This is used to sort our own positive image database as a first step before grabbing characters to use to train the OCR. - bool detectPlate( StateIdentifier* identifier, Mat frame); +bool detectPlate( StateIdentifier* identifier, Mat frame); int main( int argc, const char** argv ) { - string inDir; - string outDir; - Mat frame; - + string inDir; + string outDir; + Mat frame; //Check if user specify image to process if(argc == 3 ) { - inDir = argv[1]; - outDir = argv[2]; - outDir = outDir + "/"; + inDir = argv[1]; + outDir = argv[2]; + outDir = outDir + "/"; - - }else{ - printf("Use:\n\t%s directory \n",argv[0]); - printf("Ex: \n\t%s ./pics/ \n",argv[0]); - return 0; + } + else + { + printf("Use:\n\t%s directory \n",argv[0]); + printf("Ex: \n\t%s ./pics/ \n",argv[0]); + return 0; } Config config("us"); @@ -65,53 +65,52 @@ int main( int argc, const char** argv ) if (DirectoryExists(outDir.c_str()) == false) { - printf("Output dir does not exist\n"); - return 0; + printf("Output dir does not exist\n"); + return 0; } if (DirectoryExists(inDir.c_str())) { - vector files = getFilesInDir(inDir.c_str()); + vector files = getFilesInDir(inDir.c_str()); - for (int i = 0; i< files.size(); i++) + for (int i = 0; i< files.size(); i++) + { + if (hasEnding(files[i], ".png")) { - if (hasEnding(files[i], ".png")) - { - string fullpath = inDir + "/" + files[i]; - cout << fullpath << endl; - frame = imread( fullpath.c_str() ); + string fullpath = inDir + "/" + files[i]; + cout << fullpath << endl; + frame = imread( fullpath.c_str() ); - char code[4]; - int confidence = identifier.recognize(frame, code); + char code[4]; + int confidence = identifier.recognize(frame, code); - if (confidence <= 20) - { - code[0] = 'z'; - code[1] = 'z'; - confidence = 100; - } + if (confidence <= 20) + { + code[0] = 'z'; + code[1] = 'z'; + confidence = 100; + } - //imshow("Plate", frame); - if (confidence > 20) - { - cout << confidence << " : " << code; + //imshow("Plate", frame); + if (confidence > 20) + { + cout << confidence << " : " << code; - ostringstream convert; // stream used for the conversion - convert << i; // insert the textual representation of 'Number' in the characters in the stream - - - string copyCommand = "cp \"" + fullpath + "\" " + outDir + code + convert.str() + ".png"; - system( copyCommand.c_str() ); - waitKey(50); - //while ((char) waitKey(50) != 'c') { } - } - else - waitKey(50); - } + ostringstream convert; // stream used for the conversion + convert << i; // insert the textual representation of 'Number' in the characters in the stream + string copyCommand = "cp \"" + fullpath + "\" " + outDir + code + convert.str() + ".png"; + system( copyCommand.c_str() ); + waitKey(50); + //while ((char) waitKey(50) != 'c') { } + } + else + waitKey(50); } + + } } } - bool detectPlate( StateIdentifier* identifier, Mat frame); +bool detectPlate( StateIdentifier* identifier, Mat frame); diff --git a/src/openalpr/TRexpp.h b/src/openalpr/TRexpp.h index 430925b..29bdb3f 100644 --- a/src/openalpr/TRexpp.h +++ b/src/openalpr/TRexpp.h @@ -31,45 +31,67 @@ extern "C" { #include "trex.h" } -struct TRexParseException{TRexParseException(const TRexChar *c):desc(c){}const TRexChar *desc;}; +struct TRexParseException +{ + TRexParseException(const TRexChar *c):desc(c) {} const TRexChar *desc; +}; -class TRexpp { -public: - TRexpp() { _exp = (TRex *)0; } - ~TRexpp() { CleanUp(); } - // compiles a regular expression - void Compile(const TRexChar *pattern) { - const TRexChar *error; - CleanUp(); - if(!(_exp = trex_compile(pattern,&error))) - throw TRexParseException(error); - } - // return true if the given text match the expression - bool Match(const TRexChar* text) { - return _exp?(trex_match(_exp,text) != 0):false; - } - // Searches for the first match of the expression in a zero terminated string - bool Search(const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) { - return _exp?(trex_search(_exp,text,out_begin,out_end) != 0):false; - } - // Searches for the first match of the expression in a string sarting at text_begin and ending at text_end - bool SearchRange(const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end) { - return _exp?(trex_searchrange(_exp,text_begin,text_end,out_begin,out_end) != 0):false; - } - bool GetSubExp(int n, const TRexChar** out_begin, int *out_len) - { - TRexMatch match; - TRexBool res = _exp?(trex_getsubexp(_exp,n,&match)):TRex_False; - if(res) { - *out_begin = match.begin; - *out_len = match.len; - return true; - } - return false; - } - int GetSubExpCount() { return _exp?trex_getsubexpcount(_exp):0; } -private: - void CleanUp() { if(_exp) trex_free(_exp); _exp = (TRex *)0; } - TRex *_exp; +class TRexpp +{ + public: + TRexpp() + { + _exp = (TRex *)0; + } + ~TRexpp() + { + CleanUp(); + } + // compiles a regular expression + void Compile(const TRexChar *pattern) + { + const TRexChar *error; + CleanUp(); + if(!(_exp = trex_compile(pattern,&error))) + throw TRexParseException(error); + } + // return true if the given text match the expression + bool Match(const TRexChar* text) + { + return _exp?(trex_match(_exp,text) != 0):false; + } + // Searches for the first match of the expression in a zero terminated string + bool Search(const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) + { + return _exp?(trex_search(_exp,text,out_begin,out_end) != 0):false; + } + // Searches for the first match of the expression in a string sarting at text_begin and ending at text_end + bool SearchRange(const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end) + { + return _exp?(trex_searchrange(_exp,text_begin,text_end,out_begin,out_end) != 0):false; + } + bool GetSubExp(int n, const TRexChar** out_begin, int *out_len) + { + TRexMatch match; + TRexBool res = _exp?(trex_getsubexp(_exp,n,&match)):TRex_False; + if(res) + { + *out_begin = match.begin; + *out_len = match.len; + return true; + } + return false; + } + int GetSubExpCount() + { + return _exp?trex_getsubexpcount(_exp):0; + } + private: + void CleanUp() + { + if(_exp) trex_free(_exp); + _exp = (TRex *)0; + } + TRex *_exp; }; #endif //_TREXPP_H_ diff --git a/src/openalpr/alpr.cpp b/src/openalpr/alpr.cpp index c5e2c9e..be03f49 100644 --- a/src/openalpr/alpr.cpp +++ b/src/openalpr/alpr.cpp @@ -20,9 +20,6 @@ #include "alpr.h" #include "alpr_impl.h" - - - // ALPR code Alpr::Alpr(const std::string country, const std::string runtimeDir) @@ -40,22 +37,19 @@ std::vector Alpr::recognize(std::string filepath) } - std::vector Alpr::recognize(std::vector imageBuffer) { - // Not sure if this actually works + // Not sure if this actually works cv::Mat img = cv::imdecode(Mat(imageBuffer), 1); return impl->recognize(img); } - string Alpr::toJson(const vector< AlprResult > results) { return impl->toJson(results); } - void Alpr::setDetectRegion(bool detectRegion) { impl->setDetectRegion(detectRegion); @@ -74,11 +68,8 @@ bool Alpr::isLoaded() return true; } - - // Results code - AlprResult::AlprResult() { diff --git a/src/openalpr/alpr.h b/src/openalpr/alpr.h index 69db91f..2e69292 100644 --- a/src/openalpr/alpr.h +++ b/src/openalpr/alpr.h @@ -37,8 +37,8 @@ struct AlprPlate struct AlprCoordinate { - int x; - int y; + int x; + int y; }; class AlprResult diff --git a/src/openalpr/alpr_impl.cpp b/src/openalpr/alpr_impl.cpp index 1bab02a..22178f0 100644 --- a/src/openalpr/alpr_impl.cpp +++ b/src/openalpr/alpr_impl.cpp @@ -19,7 +19,6 @@ #include "alpr_impl.h" - AlprImpl::AlprImpl(const std::string country, const std::string runtimeDir) { config = new Config(country, runtimeDir); @@ -39,7 +38,7 @@ AlprImpl::AlprImpl(const std::string country, const std::string runtimeDir) for (int i = 0; i < platinfo.size(); i++) { - std::cout << platinfo[i]->platformName << std::endl; + std::cout << platinfo[i]->platformName << std::endl; } cv::ocl::DevicesInfo devices; @@ -68,7 +67,6 @@ AlprImpl::~AlprImpl() delete ocr; } - std::vector AlprImpl::recognize(cv::Mat img) { timespec startTime; @@ -76,100 +74,95 @@ std::vector AlprImpl::recognize(cv::Mat img) vector response; - vector plateRegions = plateDetector->detect(img); - // Recognize. for (int i = 0; i < plateRegions.size(); i++) { - timespec platestarttime; - getTime(&platestarttime); + timespec platestarttime; + getTime(&platestarttime); - LicensePlateCandidate lp(img, plateRegions[i], config); + LicensePlateCandidate lp(img, plateRegions[i], config); - lp.recognize(); + lp.recognize(); + if (lp.confidence > 10) + { + AlprResult plateResult; + plateResult.region = defaultRegion; + plateResult.regionConfidence = 0; - if (lp.confidence > 10) + for (int pointidx = 0; pointidx < 4; pointidx++) { - AlprResult plateResult; - plateResult.region = defaultRegion; - plateResult.regionConfidence = 0; - - for (int pointidx = 0; pointidx < 4; pointidx++) - { - plateResult.plate_points[pointidx].x = (int) lp.plateCorners[pointidx].x; - plateResult.plate_points[pointidx].y = (int) lp.plateCorners[pointidx].y; - } - - if (detectRegion) - { - char statecode[4]; - plateResult.regionConfidence = stateIdentifier->recognize(img, plateRegions[i], statecode); - if (plateResult.regionConfidence > 0) - { - plateResult.region = statecode; - } - } - - - ocr->performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters); - - ocr->postProcessor->analyze(plateResult.region, topN); - - //plateResult.characters = ocr->postProcessor->bestChars; - const vector ppResults = ocr->postProcessor->getResults(); - - int bestPlateIndex = 0; - - for (int pp = 0; pp < ppResults.size(); pp++) - { - if (pp >= topN) - break; - - // Set our "best plate" match to either the first entry, or the first entry with a postprocessor template match - if (bestPlateIndex == 0 && ppResults[pp].matchesTemplate) - bestPlateIndex = pp; - - if (ppResults[pp].letters.size() >= config->postProcessMinCharacters && - ppResults[pp].letters.size() <= config->postProcessMaxCharacters) - { - AlprPlate aplate; - aplate.characters = ppResults[pp].letters; - aplate.overall_confidence = ppResults[pp].totalscore; - aplate.matches_template = ppResults[pp].matchesTemplate; - plateResult.topNPlates.push_back(aplate); - } - } - plateResult.result_count = plateResult.topNPlates.size(); - - if (plateResult.topNPlates.size() > 0) - plateResult.bestPlate = plateResult.topNPlates[bestPlateIndex]; - - timespec plateEndTime; - getTime(&plateEndTime); - plateResult.processing_time_ms = diffclock(platestarttime, plateEndTime); - - if (plateResult.result_count > 0) - response.push_back(plateResult); - - if (config->debugGeneral) - { - rectangle(img, plateRegions[i], Scalar(0, 255, 0), 2); - for (int z = 0; z < 4; z++) - line(img, lp.plateCorners[z], lp.plateCorners[(z + 1) % 4], Scalar(255,0,255), 2); - } - - + plateResult.plate_points[pointidx].x = (int) lp.plateCorners[pointidx].x; + plateResult.plate_points[pointidx].y = (int) lp.plateCorners[pointidx].y; } - else + + if (detectRegion) { - if (config->debugGeneral) - rectangle(img, plateRegions[i], Scalar(0, 0, 255), 2); + char statecode[4]; + plateResult.regionConfidence = stateIdentifier->recognize(img, plateRegions[i], statecode); + if (plateResult.regionConfidence > 0) + { + plateResult.region = statecode; + } } + ocr->performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters); + + ocr->postProcessor->analyze(plateResult.region, topN); + + //plateResult.characters = ocr->postProcessor->bestChars; + const vector ppResults = ocr->postProcessor->getResults(); + + int bestPlateIndex = 0; + + for (int pp = 0; pp < ppResults.size(); pp++) + { + if (pp >= topN) + break; + + // Set our "best plate" match to either the first entry, or the first entry with a postprocessor template match + if (bestPlateIndex == 0 && ppResults[pp].matchesTemplate) + bestPlateIndex = pp; + + if (ppResults[pp].letters.size() >= config->postProcessMinCharacters && + ppResults[pp].letters.size() <= config->postProcessMaxCharacters) + { + AlprPlate aplate; + aplate.characters = ppResults[pp].letters; + aplate.overall_confidence = ppResults[pp].totalscore; + aplate.matches_template = ppResults[pp].matchesTemplate; + plateResult.topNPlates.push_back(aplate); + } + } + plateResult.result_count = plateResult.topNPlates.size(); + + if (plateResult.topNPlates.size() > 0) + plateResult.bestPlate = plateResult.topNPlates[bestPlateIndex]; + + timespec plateEndTime; + getTime(&plateEndTime); + plateResult.processing_time_ms = diffclock(platestarttime, plateEndTime); + + if (plateResult.result_count > 0) + response.push_back(plateResult); + + if (config->debugGeneral) + { + rectangle(img, plateRegions[i], Scalar(0, 255, 0), 2); + for (int z = 0; z < 4; z++) + line(img, lp.plateCorners[z], lp.plateCorners[(z + 1) % 4], Scalar(255,0,255), 2); + } + + } + else + { + if (config->debugGeneral) + rectangle(img, plateRegions[i], Scalar(0, 0, 255), 2); + } + } if (config->debugTiming) @@ -210,8 +203,6 @@ string AlprImpl::toJson(const vector< AlprResult > results) return response; } - - cJSON* AlprImpl::createJsonObj(const AlprResult* result) { cJSON *root, *coords, *candidates; @@ -228,7 +219,7 @@ cJSON* AlprImpl::createJsonObj(const AlprResult* result) cJSON_AddNumberToObject(root,"processing_time_ms", result->processing_time_ms); cJSON_AddItemToObject(root, "coordinates", coords=cJSON_CreateArray()); - for (int i=0;i<4;i++) + for (int i=0; i<4; i++) { cJSON *coords_object; coords_object = cJSON_CreateObject(); @@ -238,7 +229,6 @@ cJSON* AlprImpl::createJsonObj(const AlprResult* result) cJSON_AddItemToArray(coords, coords_object); } - cJSON_AddItemToObject(root, "candidates", candidates=cJSON_CreateArray()); for (int i = 0; i < result->topNPlates.size(); i++) { @@ -254,7 +244,6 @@ cJSON* AlprImpl::createJsonObj(const AlprResult* result) return root; } - void AlprImpl::setDetectRegion(bool detectRegion) { this->detectRegion = detectRegion; diff --git a/src/openalpr/binarize_wolf.cpp b/src/openalpr/binarize_wolf.cpp index a80fe7e..a8bf5bd 100644 --- a/src/openalpr/binarize_wolf.cpp +++ b/src/openalpr/binarize_wolf.cpp @@ -33,190 +33,192 @@ #include "binarize_wolf.h" - // ************************************************************* // glide a window across the image and // create two maps: mean and standard deviation. // ************************************************************* +float calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy) +{ -float calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy) { + float m,s,max_s; + long sum, sum_sq; + uchar foo; + int wxh = winx/2; + int wyh = winy/2; + int x_firstth= wxh; + int y_lastth = im.rows-wyh-1; + int y_firstth= wyh; + float winarea = winx*winy; - float m,s,max_s; - long sum, sum_sq; - uchar foo; - int wxh = winx/2; - int wyh = winy/2; - int x_firstth= wxh; - int y_lastth = im.rows-wyh-1; - int y_firstth= wyh; - float winarea = winx*winy; + max_s = 0; + for (int j = y_firstth ; j<=y_lastth; j++) + { + // Calculate the initial window at the beginning of the line + sum = sum_sq = 0; + for (int wy=0 ; wy max_s) + max_s = s; + map_m.fset(x_firstth, j, m); + map_s.fset(x_firstth, j, s); + // Shift the window, add and remove new/old values to the histogram + for (int i=1 ; i <= im.cols-winx; i++) + { - max_s = 0; - for (int j = y_firstth ; j<=y_lastth; j++) - { - // Calculate the initial window at the beginning of the line - sum = sum_sq = 0; - for (int wy=0 ; wy max_s) - max_s = s; - map_m.fset(x_firstth, j, m); - map_s.fset(x_firstth, j, s); + // Remove the left old column and add the right new column + for (int wy=0; wy max_s) + max_s = s; + map_m.fset(i+wxh, j, m); + map_s.fset(i+wxh, j, s); + } + } - // Shift the window, add and remove new/old values to the histogram - for (int i=1 ; i <= im.cols-winx; i++) { - - // Remove the left old column and add the right new column - for (int wy=0; wy max_s) - max_s = s; - map_m.fset(i+wxh, j, m); - map_s.fset(i+wxh, j, s); - } - } - - return max_s; + return max_s; } - /********************************************************** * The binarization routine **********************************************************/ - void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version, - int winx, int winy, float k) { + int winx, int winy, float k) +{ - float dR = BINARIZEWOLF_DEFAULTDR; + float dR = BINARIZEWOLF_DEFAULTDR; - float m, s, max_s; - float th=0; - double min_I, max_I; - int wxh = winx/2; - int wyh = winy/2; - int x_firstth= wxh; - int x_lastth = im.cols-wxh-1; - int y_lastth = im.rows-wyh-1; - int y_firstth= wyh; - int mx, my; + float m, s, max_s; + float th=0; + double min_I, max_I; + int wxh = winx/2; + int wyh = winy/2; + int x_firstth= wxh; + int x_lastth = im.cols-wxh-1; + int y_lastth = im.rows-wyh-1; + int y_firstth= wyh; + int mx, my; - // Create local statistics and store them in a float matrices - Mat map_m = Mat::zeros (im.rows, im.cols, CV_32F); - Mat map_s = Mat::zeros (im.rows, im.cols, CV_32F); - max_s = calcLocalStats (im, map_m, map_s, winx, winy); + // Create local statistics and store them in a float matrices + Mat map_m = Mat::zeros (im.rows, im.cols, CV_32F); + Mat map_s = Mat::zeros (im.rows, im.cols, CV_32F); + max_s = calcLocalStats (im, map_m, map_s, winx, winy); - minMaxLoc(im, &min_I, &max_I); + minMaxLoc(im, &min_I, &max_I); - Mat thsurf (im.rows, im.cols, CV_32F); + Mat thsurf (im.rows, im.cols, CV_32F); - // Create the threshold surface, including border processing - // ---------------------------------------------------- + // Create the threshold surface, including border processing + // ---------------------------------------------------- - for (int j = y_firstth ; j<=y_lastth; j++) { + for (int j = y_firstth ; j<=y_lastth; j++) + { - // NORMAL, NON-BORDER AREA IN THE MIDDLE OF THE WINDOW: - for (int i=0 ; i <= im.cols-winx; i++) { + // NORMAL, NON-BORDER AREA IN THE MIDDLE OF THE WINDOW: + for (int i=0 ; i <= im.cols-winx; i++) + { - m = map_m.fget(i+wxh, j); - s = map_s.fget(i+wxh, j); + m = map_m.fget(i+wxh, j); + s = map_s.fget(i+wxh, j); - // Calculate the threshold - switch (version) { + // Calculate the threshold + switch (version) + { - case NIBLACK: - th = m + k*s; - break; + case NIBLACK: + th = m + k*s; + break; - case SAUVOLA: - th = m * (1 + k*(s/dR-1)); - break; + case SAUVOLA: + th = m * (1 + k*(s/dR-1)); + break; - case WOLFJOLION: - th = m + k * (s/max_s-1) * (m-min_I); - break; + case WOLFJOLION: + th = m + k * (s/max_s-1) * (m-min_I); + break; - default: - cerr << "Unknown threshold type in ImageThresholder::surfaceNiblackImproved()\n"; - exit (1); - } + default: + cerr << "Unknown threshold type in ImageThresholder::surfaceNiblackImproved()\n"; + exit (1); + } - thsurf.fset(i+wxh,j,th); + thsurf.fset(i+wxh,j,th); - if (i==0) { - // LEFT BORDER - for (int i=0; i<=x_firstth; ++i) - thsurf.fset(i,j,th); + if (i==0) + { + // LEFT BORDER + for (int i=0; i<=x_firstth; ++i) + thsurf.fset(i,j,th); - // LEFT-UPPER CORNER - if (j==y_firstth) - for (int u=0; u= thsurf.fget(x,y)) - { - output.uset(x,y,255); - } - else - { - output.uset(x,y,0); - } + for (int y=0; y= thsurf.fget(x,y)) + { + output.uset(x,y,255); + } + else + { + output.uset(x,y,0); + } } } diff --git a/src/openalpr/binarize_wolf.h b/src/openalpr/binarize_wolf.h index fae86e0..6e85d70 100644 --- a/src/openalpr/binarize_wolf.h +++ b/src/openalpr/binarize_wolf.h @@ -32,9 +32,9 @@ using namespace cv; enum NiblackVersion { - NIBLACK=0, - SAUVOLA, - WOLFJOLION, + NIBLACK=0, + SAUVOLA, + WOLFJOLION, }; #define BINARIZEWOLF_VERSION "2.3 (February 26th, 2013)" @@ -49,7 +49,7 @@ enum NiblackVersion void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version, - int winx, int winy, float k); + int winx, int winy, float k); diff --git a/src/openalpr/characteranalysis.cpp b/src/openalpr/characteranalysis.cpp index c15a112..b9b3c39 100644 --- a/src/openalpr/characteranalysis.cpp +++ b/src/openalpr/characteranalysis.cpp @@ -29,13 +29,12 @@ CharacterAnalysis::CharacterAnalysis(Mat img, Config* config) if (this->config->debugCharAnalysis) cout << "Starting CharacterAnalysis identification" << endl; - if (img.type() != CV_8U) cvtColor( img, this->img_gray, CV_BGR2GRAY ); else { - img_gray = Mat(img.size(), img.type()); - img.copyTo(img_gray); + img_gray = Mat(img.size(), img.type()); + img.copyTo(img_gray); } } @@ -44,20 +43,16 @@ CharacterAnalysis::~CharacterAnalysis() { for (int i = 0; i < thresholds.size(); i++) { - thresholds[i].release(); + thresholds[i].release(); } thresholds.clear(); } - - void CharacterAnalysis::analyze() { - thresholds = produceThresholds(img_gray, config); - /* // Morph Close the gray image to make it easier to detect blobs int morph_elem = 1; @@ -73,11 +68,9 @@ void CharacterAnalysis::analyze() } */ - timespec startTime; getTime(&startTime); - for (int i = 0; i < thresholds.size(); i++) { vector > contours; @@ -86,18 +79,15 @@ void CharacterAnalysis::analyze() Mat tempThreshold(thresholds[i].size(), CV_8U); thresholds[i].copyTo(tempThreshold); findContours(tempThreshold, - contours, // a vector of contours - hierarchy, - CV_RETR_TREE, // retrieve all contours - CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours + contours, // a vector of contours + hierarchy, + CV_RETR_TREE, // retrieve all contours + CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours allContours.push_back(contours); allHierarchy.push_back(hierarchy); } - - - if (config->debugTiming) { timespec endTime; @@ -106,7 +96,6 @@ void CharacterAnalysis::analyze() } //Mat img_equalized = equalizeBrightness(img_gray); - getTime(&startTime); for (int i = 0; i < thresholds.size(); i++) @@ -125,8 +114,6 @@ void CharacterAnalysis::analyze() cout << " -- Character Analysis Filter Time: " << diffclock(startTime, endTime) << "ms." << endl; } - - this->plateMask = findOuterBoxMask(); if (hasPlateMask) @@ -138,7 +125,6 @@ void CharacterAnalysis::analyze() } } - int bestFitScore = -1; int bestFitIndex = -1; for (int i = 0; i < thresholds.size(); i++) @@ -149,7 +135,6 @@ void CharacterAnalysis::analyze() int segmentCount = getGoodIndicesCount(charSegments[i]); - if (segmentCount > bestFitScore) { bestFitScore = segmentCount; @@ -165,11 +150,9 @@ void CharacterAnalysis::analyze() if (this->config->debugCharAnalysis) cout << "Best fit score: " << bestFitScore << " Index: " << bestFitIndex << endl; - if (bestFitScore <= 1) return; - //getColorMask(img, allContours, allHierarchy, charSegments); if (this->config->debugCharAnalysis) @@ -182,29 +165,25 @@ void CharacterAnalysis::analyze() vector > allowedContours; for (int i = 0; i < bestContours.size(); i++) { - if (bestCharSegments[i]) - allowedContours.push_back(bestContours[i]); + if (bestCharSegments[i]) + allowedContours.push_back(bestContours[i]); } drawContours(img_contours, bestContours, - -1, // draw all contours - cv::Scalar(255,0,0), // in blue - 1); // with a thickness of 1 + -1, // draw all contours + cv::Scalar(255,0,0), // in blue + 1); // with a thickness of 1 drawContours(img_contours, allowedContours, - -1, // draw all contours - cv::Scalar(0,255,0), // in green - 1); // with a thickness of 1 - + -1, // draw all contours + cv::Scalar(0,255,0), // in green + 1); // with a thickness of 1 displayImage(config, "Matching Contours", img_contours); } - //charsegments = this->getPossibleCharRegions(img_threshold, allContours, allHierarchy, STARTING_MIN_HEIGHT + (bestFitIndex * HEIGHT_STEP), STARTING_MAX_HEIGHT + (bestFitIndex * HEIGHT_STEP)); - - this->linePolygon = getBestVotedLines(img_gray, bestContours, bestCharSegments); if (this->linePolygon.size() > 0) @@ -223,14 +202,11 @@ void CharacterAnalysis::analyze() this->charBoxLeft = LineSegment(this->charArea[3].x, this->charArea[3].y, this->charArea[0].x, this->charArea[0].y); this->charBoxRight = LineSegment(this->charArea[2].x, this->charArea[2].y, this->charArea[1].x, this->charArea[1].y); - } } this->thresholdsInverted = isPlateInverted(); - - } int CharacterAnalysis::getGoodIndicesCount(vector goodIndices) @@ -245,8 +221,6 @@ int CharacterAnalysis::getGoodIndicesCount(vector goodIndices) return count; } - - Mat CharacterAnalysis::findOuterBoxMask() { double min_parent_area = config->templateHeightPx * config->templateWidthPx * 0.10; // Needs to be at least 10% of the plate area to be considered. @@ -256,7 +230,6 @@ Mat CharacterAnalysis::findOuterBoxMask() int bestCharCount = 0; double lowestArea = 99999999999999; - if (this->config->debugCharAnalysis) cout << "CharacterAnalysis::findOuterBoxMask" << endl; @@ -272,8 +245,8 @@ Mat CharacterAnalysis::findOuterBoxMask() if (charSegments[imgIndex][i]) charsRecognized++; if (charSegments[imgIndex][i] && allHierarchy[imgIndex][i][3] != -1) { - parentId = allHierarchy[imgIndex][i][3]; - hasParent = true; + parentId = allHierarchy[imgIndex][i][3]; + hasParent = true; } } @@ -284,28 +257,24 @@ Mat CharacterAnalysis::findOuterBoxMask() { double boxArea = contourArea(allContours[imgIndex][parentId]); if (boxArea < min_parent_area) - continue; + continue; if ((charsRecognized > bestCharCount) || - (charsRecognized == bestCharCount && boxArea < lowestArea)) - //(boxArea < lowestArea) + (charsRecognized == bestCharCount && boxArea < lowestArea)) + //(boxArea < lowestArea) { - bestCharCount = charsRecognized; - winningIndex = imgIndex; - winningParentId = parentId; - lowestArea = boxArea; + bestCharCount = charsRecognized; + winningIndex = imgIndex; + winningParentId = parentId; + lowestArea = boxArea; } } - } if (this->config->debugCharAnalysis) cout << "Winning image index is: " << winningIndex << endl; - - - if (winningIndex != -1 && bestCharCount >= 3) { int longestChildIndex = -1; @@ -313,36 +282,31 @@ Mat CharacterAnalysis::findOuterBoxMask() // Find the child with the longest permiter/arc length ( just for kicks) for (int i = 0; i < allContours[winningIndex].size(); i++) { - for (int j = 0; j < allContours[winningIndex].size(); j++) - { - if (allHierarchy[winningIndex][j][3] == winningParentId) - { - double arclength = arcLength(allContours[winningIndex][j], false); - if (arclength > longestChildLength) - { - longestChildIndex = j; - longestChildLength = arclength; - } - } - } + for (int j = 0; j < allContours[winningIndex].size(); j++) + { + if (allHierarchy[winningIndex][j][3] == winningParentId) + { + double arclength = arcLength(allContours[winningIndex][j], false); + if (arclength > longestChildLength) + { + longestChildIndex = j; + longestChildLength = arclength; + } + } + } } - - - - Mat mask = Mat::zeros(thresholds[winningIndex].size(), CV_8U); // get rid of the outline by drawing a 1 pixel width black line drawContours(mask, allContours[winningIndex], - winningParentId, // draw this contour - cv::Scalar(255,255,255), // in - CV_FILLED, - 8, - allHierarchy[winningIndex], - 0 - ); - + winningParentId, // draw this contour + cv::Scalar(255,255,255), // in + CV_FILLED, + 8, + allHierarchy[winningIndex], + 0 + ); // Morph Open the mask to get rid of any little connectors to non-plate portions int morph_elem = 2; @@ -356,7 +320,6 @@ Mat CharacterAnalysis::findOuterBoxMask() //element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) ); //dilate(mask, mask, element); - // Drawing the edge black effectively erodes the image. This may clip off some extra junk from the edges. // We'll want to do the contour again and find the larges one so that we remove the clipped portion. @@ -368,33 +331,31 @@ Mat CharacterAnalysis::findOuterBoxMask() for (int c = 0; c < contoursSecondRound.size(); c++) { double area = contourArea(contoursSecondRound[c]); - if (area > largestArea) - { - biggestContourIndex = c; - largestArea = area; - } + if (area > largestArea) + { + biggestContourIndex = c; + largestArea = area; + } } if (biggestContourIndex != -1) { - mask = Mat::zeros(thresholds[winningIndex].size(), CV_8U); + mask = Mat::zeros(thresholds[winningIndex].size(), CV_8U); - vector smoothedMaskPoints; - approxPolyDP(contoursSecondRound[biggestContourIndex], smoothedMaskPoints, 2, true); + vector smoothedMaskPoints; + approxPolyDP(contoursSecondRound[biggestContourIndex], smoothedMaskPoints, 2, true); - vector > tempvec; - tempvec.push_back(smoothedMaskPoints); - //fillPoly(mask, smoothedMaskPoints.data(), smoothedMaskPoints, Scalar(255,255,255)); + vector > tempvec; + tempvec.push_back(smoothedMaskPoints); + //fillPoly(mask, smoothedMaskPoints.data(), smoothedMaskPoints, Scalar(255,255,255)); drawContours(mask, tempvec, - 0, // draw this contour - cv::Scalar(255,255,255), // in - CV_FILLED, - 8, - allHierarchy[winningIndex], - 0 - ); - - + 0, // draw this contour + cv::Scalar(255,255,255), // in + CV_FILLED, + 8, + allHierarchy[winningIndex], + 0 + ); } @@ -422,48 +383,41 @@ Mat CharacterAnalysis::findOuterBoxMask() bitwise_not(fullMask, fullMask); return fullMask; - - } - Mat CharacterAnalysis::getCharacterMask() { - Mat charMask = Mat::zeros(bestThreshold.size(), CV_8U); + Mat charMask = Mat::zeros(bestThreshold.size(), CV_8U); - for (int i = 0; i < bestContours.size(); i++) - { - if (bestCharSegments[i] == false) - continue; + for (int i = 0; i < bestContours.size(); i++) + { + if (bestCharSegments[i] == false) + continue; + drawContours(charMask, bestContours, + i, // draw this contour + cv::Scalar(255,255,255), // in + CV_FILLED, + 8, + bestHierarchy, + 1 + ); - drawContours(charMask, bestContours, - i, // draw this contour - cv::Scalar(255,255,255), // in - CV_FILLED, - 8, - bestHierarchy, - 1 - ); + // get rid of the outline by drawing a 1 pixel width black line + drawContours(charMask, bestContours, + i, // draw this contour + cv::Scalar(0,0,0), // in + 1, + 8, + bestHierarchy, + 1 + ); + } - // get rid of the outline by drawing a 1 pixel width black line - drawContours(charMask, bestContours, - i, // draw this contour - cv::Scalar(0,0,0), // in - 1, - 8, - bestHierarchy, - 1 - ); - } - - - return charMask; + return charMask; } - - // Returns a polygon "stripe" across the width of the character region. The lines are voted and the polygon starts at 0 and extends to image width vector CharacterAnalysis::getBestVotedLines(Mat img, vector > contours, vector goodIndices) { @@ -481,161 +435,150 @@ vector CharacterAnalysis::getBestVotedLines(Mat img, vector charRegions.push_back(boundingRect(contours[i])); } - - // Find the best fit line segment that is parallel with the most char segments - if (charRegions.size() <= 1) + // Find the best fit line segment that is parallel with the most char segments + if (charRegions.size() <= 1) + { + // Maybe do something about this later, for now let's just ignore + } + else + { + vector topLines; + vector bottomLines; + // Iterate through each possible char and find all possible lines for the top and bottom of each char segment + for (int i = 0; i < charRegions.size() - 1; i++) { - // Maybe do something about this later, for now let's just ignore - } - else - { - vector topLines; - vector bottomLines; - // Iterate through each possible char and find all possible lines for the top and bottom of each char segment - for (int i = 0; i < charRegions.size() - 1; i++) + for (int k = i+1; k < charRegions.size(); k++) { - for (int k = i+1; k < charRegions.size(); k++) - { - //Mat tempImg; - //result.copyTo(tempImg); + //Mat tempImg; + //result.copyTo(tempImg); + Rect* leftRect; + Rect* rightRect; + if (charRegions[i].x < charRegions[k].x) + { + leftRect = &charRegions[i]; + rightRect = &charRegions[k]; + } + else + { + leftRect = &charRegions[k]; + rightRect = &charRegions[i]; + } - Rect* leftRect; - Rect* rightRect; - if (charRegions[i].x < charRegions[k].x) - { - leftRect = &charRegions[i]; - rightRect = &charRegions[k]; - } - else - { - leftRect = &charRegions[k]; - rightRect = &charRegions[i]; - } + //rectangle(tempImg, *leftRect, Scalar(0, 255, 0), 2); + //rectangle(tempImg, *rightRect, Scalar(255, 255, 255), 2); - //rectangle(tempImg, *leftRect, Scalar(0, 255, 0), 2); - //rectangle(tempImg, *rightRect, Scalar(255, 255, 255), 2); + int x1, y1, x2, y2; - int x1, y1, x2, y2; + if (leftRect->y > rightRect->y) // Rising line, use the top left corner of the rect + { + x1 = leftRect->x; + x2 = rightRect->x; + } + else // falling line, use the top right corner of the rect + { + x1 = leftRect->x + leftRect->width; + x2 = rightRect->x + rightRect->width; + } + y1 = leftRect->y; + y2 = rightRect->y; - if (leftRect->y > rightRect->y) // Rising line, use the top left corner of the rect - { - x1 = leftRect->x; - x2 = rightRect->x; - } - else // falling line, use the top right corner of the rect - { - x1 = leftRect->x + leftRect->width; - x2 = rightRect->x + rightRect->width; - } - y1 = leftRect->y; - y2 = rightRect->y; + //cv::line(tempImg, Point(x1, y1), Point(x2, y2), Scalar(0, 0, 255)); + topLines.push_back(LineSegment(x1, y1, x2, y2)); - //cv::line(tempImg, Point(x1, y1), Point(x2, y2), Scalar(0, 0, 255)); - topLines.push_back(LineSegment(x1, y1, x2, y2)); + if (leftRect->y > rightRect->y) // Rising line, use the bottom right corner of the rect + { + x1 = leftRect->x + leftRect->width; + x2 = rightRect->x + rightRect->width; + } + else // falling line, use the bottom left corner of the rect + { + x1 = leftRect->x; + x2 = rightRect->x; + } + y1 = leftRect->y + leftRect->height; + y2 = rightRect->y + leftRect->height; + //cv::line(tempImg, Point(x1, y1), Point(x2, y2), Scalar(0, 0, 255)); + bottomLines.push_back(LineSegment(x1, y1, x2, y2)); - if (leftRect->y > rightRect->y) // Rising line, use the bottom right corner of the rect - { - x1 = leftRect->x + leftRect->width; - x2 = rightRect->x + rightRect->width; - } - else // falling line, use the bottom left corner of the rect - { - x1 = leftRect->x; - x2 = rightRect->x; - } - y1 = leftRect->y + leftRect->height; - y2 = rightRect->y + leftRect->height; - - //cv::line(tempImg, Point(x1, y1), Point(x2, y2), Scalar(0, 0, 255)); - bottomLines.push_back(LineSegment(x1, y1, x2, y2)); - - //drawAndWait(&tempImg); - } + //drawAndWait(&tempImg); } - - int bestScoreIndex = 0; - int bestScore = -1; - int bestScoreDistance = -1; // Line segment distance is used as a tie breaker - - // Now, among all possible lines, find the one that is the best fit - for (int i = 0; i < topLines.size(); i++) - { - float SCORING_MIN_THRESHOLD = 0.97; - float SCORING_MAX_THRESHOLD = 1.03; - - - int curScore = 0; - for (int charidx = 0; charidx < charRegions.size(); charidx++) - { - - float topYPos = topLines[i].getPointAt(charRegions[charidx].x); - float botYPos = bottomLines[i].getPointAt(charRegions[charidx].x); - - float minTop = charRegions[charidx].y * SCORING_MIN_THRESHOLD; - float maxTop = charRegions[charidx].y * SCORING_MAX_THRESHOLD; - float minBot = (charRegions[charidx].y + charRegions[charidx].height) * SCORING_MIN_THRESHOLD; - float maxBot = (charRegions[charidx].y + charRegions[charidx].height) * SCORING_MAX_THRESHOLD; - if ( (topYPos >= minTop && topYPos <= maxTop) && - (botYPos >= minBot && botYPos <= maxBot)) - { - curScore++; - } - - //cout << "Slope: " << topslope << " yPos: " << topYPos << endl; - //drawAndWait(&tempImg); - - } - - - // Tie goes to the one with longer line segments - if ((curScore > bestScore) || - (curScore == bestScore && topLines[i].length > bestScoreDistance)) - { - bestScore = curScore; - bestScoreIndex = i; - // Just use x distance for now - bestScoreDistance = topLines[i].length; - } - } - - - if (this->config->debugCharAnalysis) - { - cout << "The winning score is: " << bestScore << endl; - // Draw the winning line segment - //Mat tempImg; - //result.copyTo(tempImg); - //cv::line(tempImg, topLines[bestScoreIndex].p1, topLines[bestScoreIndex].p2, Scalar(0, 0, 255), 2); - //cv::line(tempImg, bottomLines[bestScoreIndex].p1, bottomLines[bestScoreIndex].p2, Scalar(0, 0, 255), 2); - - //displayImage(config, "Lines", tempImg); - } - - //winningLines.push_back(topLines[bestScoreIndex]); - //winningLines.push_back(bottomLines[bestScoreIndex]); - - Point topLeft = Point(0, topLines[bestScoreIndex].getPointAt(0) ); - Point topRight = Point(img.cols, topLines[bestScoreIndex].getPointAt(img.cols)); - Point bottomRight = Point(img.cols, bottomLines[bestScoreIndex].getPointAt(img.cols)); - Point bottomLeft = Point(0, bottomLines[bestScoreIndex].getPointAt(0)); - - - bestStripe.push_back(topLeft); - bestStripe.push_back(topRight); - bestStripe.push_back(bottomRight); - bestStripe.push_back(bottomLeft); - - } + int bestScoreIndex = 0; + int bestScore = -1; + int bestScoreDistance = -1; // Line segment distance is used as a tie breaker - return bestStripe; + // Now, among all possible lines, find the one that is the best fit + for (int i = 0; i < topLines.size(); i++) + { + float SCORING_MIN_THRESHOLD = 0.97; + float SCORING_MAX_THRESHOLD = 1.03; + + int curScore = 0; + for (int charidx = 0; charidx < charRegions.size(); charidx++) + { + + float topYPos = topLines[i].getPointAt(charRegions[charidx].x); + float botYPos = bottomLines[i].getPointAt(charRegions[charidx].x); + + float minTop = charRegions[charidx].y * SCORING_MIN_THRESHOLD; + float maxTop = charRegions[charidx].y * SCORING_MAX_THRESHOLD; + float minBot = (charRegions[charidx].y + charRegions[charidx].height) * SCORING_MIN_THRESHOLD; + float maxBot = (charRegions[charidx].y + charRegions[charidx].height) * SCORING_MAX_THRESHOLD; + if ( (topYPos >= minTop && topYPos <= maxTop) && + (botYPos >= minBot && botYPos <= maxBot)) + { + curScore++; + } + + //cout << "Slope: " << topslope << " yPos: " << topYPos << endl; + //drawAndWait(&tempImg); + + } + + // Tie goes to the one with longer line segments + if ((curScore > bestScore) || + (curScore == bestScore && topLines[i].length > bestScoreDistance)) + { + bestScore = curScore; + bestScoreIndex = i; + // Just use x distance for now + bestScoreDistance = topLines[i].length; + } + } + + if (this->config->debugCharAnalysis) + { + cout << "The winning score is: " << bestScore << endl; + // Draw the winning line segment + //Mat tempImg; + //result.copyTo(tempImg); + //cv::line(tempImg, topLines[bestScoreIndex].p1, topLines[bestScoreIndex].p2, Scalar(0, 0, 255), 2); + //cv::line(tempImg, bottomLines[bestScoreIndex].p1, bottomLines[bestScoreIndex].p2, Scalar(0, 0, 255), 2); + + //displayImage(config, "Lines", tempImg); + } + + //winningLines.push_back(topLines[bestScoreIndex]); + //winningLines.push_back(bottomLines[bestScoreIndex]); + + Point topLeft = Point(0, topLines[bestScoreIndex].getPointAt(0) ); + Point topRight = Point(img.cols, topLines[bestScoreIndex].getPointAt(img.cols)); + Point bottomRight = Point(img.cols, bottomLines[bestScoreIndex].getPointAt(img.cols)); + Point bottomLeft = Point(0, bottomLines[bestScoreIndex].getPointAt(0)); + + bestStripe.push_back(topLeft); + bestStripe.push_back(topRight); + bestStripe.push_back(bottomRight); + bestStripe.push_back(bottomLeft); + + } + + return bestStripe; } - - vector CharacterAnalysis::filter(Mat img, vector > contours, vector hierarchy) { static int STARTING_MIN_HEIGHT = round (((float) img.rows) * config->charAnalysisMinPercent); @@ -643,7 +586,6 @@ vector CharacterAnalysis::filter(Mat img, vector > contours, static int HEIGHT_STEP = round (((float) img.rows) * config->charAnalysisHeightStepSize); static int NUM_STEPS = config->charAnalysisNumSteps; - vector charSegments; int bestFitScore = -1; for (int i = 0; i < NUM_STEPS; i++) @@ -655,7 +597,6 @@ vector CharacterAnalysis::filter(Mat img, vector > contours, goodIndices = this->filterByBoxSize(contours, goodIndices, STARTING_MIN_HEIGHT + (i * HEIGHT_STEP), STARTING_MAX_HEIGHT + (i * HEIGHT_STEP)); - goodIndicesCount = getGoodIndicesCount(goodIndices); if ( goodIndicesCount > 0 && goodIndicesCount <= bestFitScore) // Don't bother doing more filtering if we already lost... continue; @@ -668,7 +609,6 @@ vector CharacterAnalysis::filter(Mat img, vector > contours, vector lines = getBestVotedLines(img, contours, goodIndices); goodIndices = this->filterBetweenLines(img, contours, hierarchy, lines, goodIndices); - int segmentCount = getGoodIndicesCount(goodIndices); if (segmentCount > bestFitScore) @@ -678,227 +618,216 @@ vector CharacterAnalysis::filter(Mat img, vector > contours, } } - return charSegments; } - // Goes through the contours for the plate and picks out possible char segments based on min/max height vector CharacterAnalysis::filterByBoxSize(vector< vector< Point> > contours, vector goodIndices, int minHeightPx, int maxHeightPx) { - float idealAspect=config->charWidthMM / config->charHeightMM; - float aspecttolerance=0.25; + float idealAspect=config->charWidthMM / config->charHeightMM; + float aspecttolerance=0.25; + vector includedIndices(contours.size()); + for (int j = 0; j < contours.size(); j++) + includedIndices.push_back(false); - vector includedIndices(contours.size()); - for (int j = 0; j < contours.size(); j++) - includedIndices.push_back(false); + for (int i = 0; i < contours.size(); i++) + { + if (goodIndices[i] == false) + continue; - for (int i = 0; i < contours.size(); i++) + //Create bounding rect of object + Rect mr= boundingRect(contours[i]); + + float minWidth = mr.height * 0.2; + //Crop image + //Mat auxRoi(img, mr); + if(mr.height >= minHeightPx && mr.height <= maxHeightPx && mr.width > minWidth) { - if (goodIndices[i] == false) - continue; - //Create bounding rect of object - Rect mr= boundingRect(contours[i]); + float charAspect= (float)mr.width/(float)mr.height; - float minWidth = mr.height * 0.2; - //Crop image - //Mat auxRoi(img, mr); - if(mr.height >= minHeightPx && mr.height <= maxHeightPx && mr.width > minWidth){ - - float charAspect= (float)mr.width/(float)mr.height; - - if (abs(charAspect - idealAspect) < aspecttolerance) - includedIndices[i] = true; - } + if (abs(charAspect - idealAspect) < aspecttolerance) + includedIndices[i] = true; } + } - return includedIndices; + return includedIndices; } - - vector< bool > CharacterAnalysis::filterContourHoles(vector< vector< Point > > contours, vector< Vec4i > hierarchy, vector< bool > goodIndices) { - vector includedIndices(contours.size()); - for (int j = 0; j < contours.size(); j++) - includedIndices.push_back(false); + vector includedIndices(contours.size()); + for (int j = 0; j < contours.size(); j++) + includedIndices.push_back(false); - for (int i = 0; i < contours.size(); i++) + for (int i = 0; i < contours.size(); i++) + { + if (goodIndices[i] == false) + continue; + + int parentIndex = hierarchy[i][3]; + + if (parentIndex >= 0 && goodIndices[parentIndex] == true) { - if (goodIndices[i] == false) - continue; - - int parentIndex = hierarchy[i][3]; - - if (parentIndex >= 0 && goodIndices[parentIndex] == true) - { - // this contour is a child of an already identified contour. REMOVE it - if (this->config->debugCharAnalysis) - { - cout << "filterContourHoles: contour index: " << i << endl; - } - } - else - { - includedIndices[i] = true; - } + // this contour is a child of an already identified contour. REMOVE it + if (this->config->debugCharAnalysis) + { + cout << "filterContourHoles: contour index: " << i << endl; + } } + else + { + includedIndices[i] = true; + } + } - return includedIndices; + return includedIndices; } - // Goes through the contours for the plate and picks out possible char segments based on min/max height // returns a vector of indices corresponding to valid contours vector CharacterAnalysis::filterByParentContour( vector< vector< Point> > contours, vector hierarchy, vector goodIndices) { - vector includedIndices(contours.size()); - for (int j = 0; j < contours.size(); j++) - includedIndices[j] = false; + vector includedIndices(contours.size()); + for (int j = 0; j < contours.size(); j++) + includedIndices[j] = false; - vector parentIDs; - vector votes; + vector parentIDs; + vector votes; - for (int i = 0; i < contours.size(); i++) + for (int i = 0; i < contours.size(); i++) + { + if (goodIndices[i] == false) + continue; + + int voteIndex = -1; + int parentID = hierarchy[i][3]; + // check if parentID is already in the lsit + for (int j = 0; j < parentIDs.size(); j++) { - if (goodIndices[i] == false) - continue; - - int voteIndex = -1; - int parentID = hierarchy[i][3]; - // check if parentID is already in the lsit - for (int j = 0; j < parentIDs.size(); j++) - { - if (parentIDs[j] == parentID) - { - voteIndex = j; - break; - } - } - if (voteIndex == -1) - { - parentIDs.push_back(parentID); - votes.push_back(1); - } - else - { - votes[voteIndex] = votes[voteIndex] + 1; - } - - } - - // Tally up the votes, pick the winner - int totalVotes = 0; - int winningParentId = 0; - int highestVotes = 0; - for (int i = 0; i < parentIDs.size(); i++) - { - if (votes[i] > highestVotes) + if (parentIDs[j] == parentID) { - winningParentId = parentIDs[i]; - highestVotes = votes[i]; + voteIndex = j; + break; } - totalVotes += votes[i]; } - - // Now filter out all the contours with a different parent ID (assuming the totalVotes > 2) - for (int i = 0; i < contours.size(); i++) + if (voteIndex == -1) { - if (goodIndices[i] == false) - continue; - - if (totalVotes <= 2) - { - includedIndices[i] = true; - } - else if (hierarchy[i][3] == winningParentId) - { - includedIndices[i] = true; - } + parentIDs.push_back(parentID); + votes.push_back(1); + } + else + { + votes[voteIndex] = votes[voteIndex] + 1; } - return includedIndices; -} + } + // Tally up the votes, pick the winner + int totalVotes = 0; + int winningParentId = 0; + int highestVotes = 0; + for (int i = 0; i < parentIDs.size(); i++) + { + if (votes[i] > highestVotes) + { + winningParentId = parentIDs[i]; + highestVotes = votes[i]; + } + totalVotes += votes[i]; + } + + // Now filter out all the contours with a different parent ID (assuming the totalVotes > 2) + for (int i = 0; i < contours.size(); i++) + { + if (goodIndices[i] == false) + continue; + + if (totalVotes <= 2) + { + includedIndices[i] = true; + } + else if (hierarchy[i][3] == winningParentId) + { + includedIndices[i] = true; + } + } + + return includedIndices; +} vector CharacterAnalysis::filterBetweenLines(Mat img, vector > contours, vector hierarchy, vector outerPolygon, vector goodIndices) { - static float MIN_AREA_PERCENT_WITHIN_LINES = 0.88; + static float MIN_AREA_PERCENT_WITHIN_LINES = 0.88; - vector includedIndices(contours.size()); - for (int j = 0; j < contours.size(); j++) - includedIndices[j] = false; + vector includedIndices(contours.size()); + for (int j = 0; j < contours.size(); j++) + includedIndices[j] = false; + if (outerPolygon.size() == 0) + return includedIndices; - if (outerPolygon.size() == 0) - return includedIndices; + vector validPoints; - vector validPoints; + // Figure out the line height + LineSegment topLine(outerPolygon[0].x, outerPolygon[0].y, outerPolygon[1].x, outerPolygon[1].y); + LineSegment bottomLine(outerPolygon[3].x, outerPolygon[3].y, outerPolygon[2].x, outerPolygon[2].y); - // Figure out the line height - LineSegment topLine(outerPolygon[0].x, outerPolygon[0].y, outerPolygon[1].x, outerPolygon[1].y); - LineSegment bottomLine(outerPolygon[3].x, outerPolygon[3].y, outerPolygon[2].x, outerPolygon[2].y); + float x = ((float) img.cols) / 2; + Point midpoint = Point(x, bottomLine.getPointAt(x)); + Point acrossFromMidpoint = topLine.closestPointOnSegmentTo(midpoint); + float lineHeight = distanceBetweenPoints(midpoint, acrossFromMidpoint); - float x = ((float) img.cols) / 2; - Point midpoint = Point(x, bottomLine.getPointAt(x)); - Point acrossFromMidpoint = topLine.closestPointOnSegmentTo(midpoint); - float lineHeight = distanceBetweenPoints(midpoint, acrossFromMidpoint); + // Create a white mask for the area inside the polygon + Mat outerMask = Mat::zeros(img.size(), CV_8U); + Mat innerArea = Mat::zeros(img.size(), CV_8U); + fillConvexPoly(outerMask, outerPolygon.data(), outerPolygon.size(), Scalar(255,255,255)); - // Create a white mask for the area inside the polygon - Mat outerMask = Mat::zeros(img.size(), CV_8U); - Mat innerArea = Mat::zeros(img.size(), CV_8U); - fillConvexPoly(outerMask, outerPolygon.data(), outerPolygon.size(), Scalar(255,255,255)); + for (int i = 0; i < contours.size(); i++) + { + if (goodIndices[i] == false) + continue; + // get rid of the outline by drawing a 1 pixel width black line + drawContours(innerArea, contours, + i, // draw this contour + cv::Scalar(255,255,255), // in + CV_FILLED, + 8, + hierarchy, + 0 + ); - for (int i = 0; i < contours.size(); i++) + bitwise_and(innerArea, outerMask, innerArea); + + vector > tempContours; + findContours(innerArea, tempContours, + CV_RETR_EXTERNAL, // retrieve the external contours + CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours ); + + double totalArea = contourArea(contours[i]); + double areaBetweenLines = 0; + + for (int tempContourIdx = 0; tempContourIdx < tempContours.size(); tempContourIdx++) { - if (goodIndices[i] == false) - continue; + areaBetweenLines += contourArea(tempContours[tempContourIdx]); - // get rid of the outline by drawing a 1 pixel width black line - drawContours(innerArea, contours, - i, // draw this contour - cv::Scalar(255,255,255), // in - CV_FILLED, - 8, - hierarchy, - 0 - ); - - - bitwise_and(innerArea, outerMask, innerArea); - - - vector > tempContours; - findContours(innerArea, tempContours, - CV_RETR_EXTERNAL, // retrieve the external contours - CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours ); - - double totalArea = contourArea(contours[i]); - double areaBetweenLines = 0; - - for (int tempContourIdx = 0; tempContourIdx < tempContours.size(); tempContourIdx++) - { - areaBetweenLines += contourArea(tempContours[tempContourIdx]); - - } - - - if (areaBetweenLines / totalArea >= MIN_AREA_PERCENT_WITHIN_LINES) - { - includedIndices[i] = true; - } - - innerArea.setTo(Scalar(0,0,0)); } - return includedIndices; + if (areaBetweenLines / totalArea >= MIN_AREA_PERCENT_WITHIN_LINES) + { + includedIndices[i] = true; + } + + innerArea.setTo(Scalar(0,0,0)); + } + + return includedIndices; } std::vector< bool > CharacterAnalysis::filterByOuterMask(vector< vector< Point > > contours, vector< Vec4i > hierarchy, std::vector< bool > goodIndices) @@ -909,7 +838,6 @@ std::vector< bool > CharacterAnalysis::filterByOuterMask(vector< vector< Point > if (hasPlateMask == false) return goodIndices; - vector passingIndices; for (int i = 0; i < goodIndices.size(); i++) passingIndices.push_back(false); @@ -935,8 +863,8 @@ std::vector< bool > CharacterAnalysis::filterByOuterMask(vector< vector< Point > if (afterMaskWhiteness / beforeMaskWhiteness > MINIMUM_PERCENT_LEFT_AFTER_MASK) { - charsInsideMask++; - passingIndices[i] = true; + charsInsideMask++; + passingIndices[i] = true; } } @@ -952,8 +880,6 @@ std::vector< bool > CharacterAnalysis::filterByOuterMask(vector< vector< Point > return passingIndices; } - - bool CharacterAnalysis::isPlateInverted() { @@ -964,42 +890,39 @@ bool CharacterAnalysis::isPlateInverted() if (this->config->debugCharAnalysis) cout << "CharacterAnalysis, plate inverted: MEAN: " << meanVal << " : " << bestThreshold.type() << endl; - if (meanVal[0] < 100) // Half would be 122.5. Give it a little extra oomf before saying it needs inversion. Most states aren't inverted. return true; return false; } - bool CharacterAnalysis::verifySize(Mat r, float minHeightPx, float maxHeightPx) { - //Char sizes 45x90 - float aspect=config->charWidthMM / config->charHeightMM; - float charAspect= (float)r.cols/(float)r.rows; - float error=0.35; - //float minHeight=TEMPLATE_PLATE_HEIGHT * .35; - //float maxHeight=TEMPLATE_PLATE_HEIGHT * .65; - //We have a different aspect ratio for number 1, and it can be ~0.2 - float minAspect=0.2; - float maxAspect=aspect+aspect*error; - //area of pixels - float area=countNonZero(r); - //bb area - float bbArea=r.cols*r.rows; - //% of pixel in area - float percPixels=area/bbArea; + //Char sizes 45x90 + float aspect=config->charWidthMM / config->charHeightMM; + float charAspect= (float)r.cols/(float)r.rows; + float error=0.35; + //float minHeight=TEMPLATE_PLATE_HEIGHT * .35; + //float maxHeight=TEMPLATE_PLATE_HEIGHT * .65; + //We have a different aspect ratio for number 1, and it can be ~0.2 + float minAspect=0.2; + float maxAspect=aspect+aspect*error; + //area of pixels + float area=countNonZero(r); + //bb area + float bbArea=r.cols*r.rows; + //% of pixel in area + float percPixels=area/bbArea; - //if(DEBUG) - //cout << "Aspect: "<< aspect << " ["<< minAspect << "," << maxAspect << "] " << "Area "<< percPixels <<" Char aspect " << charAspect << " Height char "<< r.rows << "\n"; - if(percPixels < 0.8 && charAspect > minAspect && charAspect < maxAspect && r.rows >= minHeightPx && r.rows < maxHeightPx) - return true; - else - return false; + //if(DEBUG) + //cout << "Aspect: "<< aspect << " ["<< minAspect << "," << maxAspect << "] " << "Area "<< percPixels <<" Char aspect " << charAspect << " Height char "<< r.rows << "\n"; + if(percPixels < 0.8 && charAspect > minAspect && charAspect < maxAspect && r.rows >= minHeightPx && r.rows < maxHeightPx) + return true; + else + return false; } - vector CharacterAnalysis::getCharArea() { const int MAX = 100000; @@ -1010,16 +933,16 @@ vector CharacterAnalysis::getCharArea() for (int i = 0; i < bestContours.size(); i++) { - if (bestCharSegments[i] == false) - continue; + if (bestCharSegments[i] == false) + continue; - for (int z = 0; z < bestContours[i].size(); z++) - { - if (bestContours[i][z].x < leftX) - leftX = bestContours[i][z].x; - if (bestContours[i][z].x > rightX) - rightX = bestContours[i][z].x; - } + for (int z = 0; z < bestContours[i].size(); z++) + { + if (bestContours[i][z].x < leftX) + leftX = bestContours[i][z].x; + if (bestContours[i][z].x > rightX) + rightX = bestContours[i][z].x; + } } vector charArea; @@ -1029,10 +952,10 @@ vector CharacterAnalysis::getCharArea() Point tr(rightX, topLine.getPointAt(rightX)); Point br(rightX, bottomLine.getPointAt(rightX)); Point bl(leftX, bottomLine.getPointAt(leftX)); - charArea.push_back(tl); - charArea.push_back(tr); - charArea.push_back(br); - charArea.push_back(bl); + charArea.push_back(tl); + charArea.push_back(tr); + charArea.push_back(br); + charArea.push_back(bl); } return charArea; diff --git a/src/openalpr/characterregion.cpp b/src/openalpr/characterregion.cpp index 9660c73..5146d75 100644 --- a/src/openalpr/characterregion.cpp +++ b/src/openalpr/characterregion.cpp @@ -28,19 +28,15 @@ CharacterRegion::CharacterRegion(Mat img, Config* config) this->confidence = 0; - - if (this->debug) cout << "Starting CharacterRegion identification" << endl; timespec startTime; getTime(&startTime); - charAnalysis = new CharacterAnalysis(img, config); charAnalysis->analyze(); - if (this->debug) { vector tempDash; @@ -53,7 +49,6 @@ CharacterRegion::CharacterRegion(Mat img, Config* config) tempDash.push_back(tmp); } - Mat bestVal(charAnalysis->bestThreshold.size(), charAnalysis->bestThreshold.type()); charAnalysis->bestThreshold.copyTo(bestVal); cvtColor(bestVal, bestVal, CV_GRAY2BGR); @@ -62,18 +57,16 @@ CharacterRegion::CharacterRegion(Mat img, Config* config) { Scalar dcolor(255,0,0); if (charAnalysis->bestCharSegments[z]) - dcolor = Scalar(0,255,0); + dcolor = Scalar(0,255,0); drawContours(bestVal, charAnalysis->bestContours, z, dcolor, 1); } tempDash.push_back(bestVal); displayImage(config, "Character Region Step 1 Thresholds", drawImageDashboard(tempDash, bestVal.type(), 3)); } - - if (this->debug) { - /* + /* Mat img_contours(img_threshold.size(), CV_8U); img_threshold.copyTo(img_contours); cvtColor(img_contours, img_contours, CV_GRAY2RGB); @@ -81,29 +74,26 @@ CharacterRegion::CharacterRegion(Mat img, Config* config) vector > allowedContours; for (int i = 0; i < contours.size(); i++) { - if (charSegments[i]) - allowedContours.push_back(contours[i]); + if (charSegments[i]) + allowedContours.push_back(contours[i]); } drawContours(img_contours, contours, - -1, // draw all contours - cv::Scalar(255,0,0), // in blue - 1); // with a thickness of 1 + -1, // draw all contours + cv::Scalar(255,0,0), // in blue + 1); // with a thickness of 1 drawContours(img_contours, allowedContours, - -1, // draw all contours - cv::Scalar(0,255,0), // in green - 1); // with a thickness of 1 - + -1, // draw all contours + cv::Scalar(0,255,0), // in green + 1); // with a thickness of 1 displayImage(config, "Matching Contours", img_contours); */ } - //charsegments = this->getPossibleCharRegions(img_threshold, allContours, allHierarchy, STARTING_MIN_HEIGHT + (bestFitIndex * HEIGHT_STEP), STARTING_MAX_HEIGHT + (bestFitIndex * HEIGHT_STEP)); - if (charAnalysis->linePolygon.size() > 0) { @@ -120,7 +110,6 @@ CharacterRegion::CharacterRegion(Mat img, Config* config) else if (absangle > 1) confidenceDrainers += (10 - absangle) * 5; - if (confidenceDrainers >= 100) this->confidence=1; else @@ -128,8 +117,6 @@ CharacterRegion::CharacterRegion(Mat img, Config* config) } - - if (config->debugTiming) { timespec endTime; @@ -144,49 +131,47 @@ CharacterRegion::~CharacterRegion() delete(charAnalysis); } - - Mat CharacterRegion::getPlateMask() { - return charAnalysis->plateMask; + return charAnalysis->plateMask; } LineSegment CharacterRegion::getTopLine() { - return charAnalysis->topLine; + return charAnalysis->topLine; } LineSegment CharacterRegion::getBottomLine() { - return charAnalysis->bottomLine; + return charAnalysis->bottomLine; } vector CharacterRegion::getCharArea() { - return charAnalysis->charArea; + return charAnalysis->charArea; } LineSegment CharacterRegion::getCharBoxTop() { - return charAnalysis->charBoxTop; + return charAnalysis->charBoxTop; } LineSegment CharacterRegion::getCharBoxBottom() { - return charAnalysis->charBoxBottom; + return charAnalysis->charBoxBottom; } LineSegment CharacterRegion::getCharBoxLeft() { - return charAnalysis->charBoxLeft; + return charAnalysis->charBoxLeft; } LineSegment CharacterRegion::getCharBoxRight() { - return charAnalysis->charBoxRight; + return charAnalysis->charBoxRight; } bool CharacterRegion::thresholdsInverted() { - return charAnalysis->thresholdsInverted; + return charAnalysis->thresholdsInverted; } diff --git a/src/openalpr/charactersegmenter.cpp b/src/openalpr/charactersegmenter.cpp index 81777eb..3eef1de 100644 --- a/src/openalpr/charactersegmenter.cpp +++ b/src/openalpr/charactersegmenter.cpp @@ -34,7 +34,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con timespec startTime; getTime(&startTime); - Mat img_gray(img.size(), CV_8U); cvtColor( img, img_gray, CV_BGR2GRAY ); @@ -43,22 +42,14 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con if (invertedColors) bitwise_not(img_gray, img_gray); - charAnalysis = new CharacterAnalysis(img_gray, config); charAnalysis->analyze(); - - if (this->config->debugCharSegmenter) { - displayImage(config, "CharacterSegmenter Thresholds", drawImageDashboard(charAnalysis->thresholds, CV_8U, 3)); + displayImage(config, "CharacterSegmenter Thresholds", drawImageDashboard(charAnalysis->thresholds, CV_8U, 3)); } - - - - - if (this->config->debugCharSegmenter) { @@ -69,19 +60,19 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con vector > allowedContours; for (int i = 0; i < charAnalysis->bestContours.size(); i++) { - if (charAnalysis->bestCharSegments[i]) - allowedContours.push_back(charAnalysis->bestContours[i]); + if (charAnalysis->bestCharSegments[i]) + allowedContours.push_back(charAnalysis->bestContours[i]); } drawContours(img_contours, charAnalysis->bestContours, - -1, // draw all contours - cv::Scalar(255,0,0), // in blue - 1); // with a thickness of 1 + -1, // draw all contours + cv::Scalar(255,0,0), // in blue + 1); // with a thickness of 1 drawContours(img_contours, allowedContours, - -1, // draw all contours - cv::Scalar(0,255,0), // in green - 1); // with a thickness of 1 + -1, // draw all contours + cv::Scalar(0,255,0), // in green + 1); // with a thickness of 1 if (charAnalysis->linePolygon.size() > 0) { @@ -93,8 +84,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con imgDbgGeneral.push_back(bordered); } - - if (charAnalysis->linePolygon.size() > 0) { this->top = LineSegment(charAnalysis->linePolygon[0].x, charAnalysis->linePolygon[0].y, charAnalysis->linePolygon[1].x, charAnalysis->linePolygon[1].y); @@ -105,14 +94,13 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con for (int i = 0; i < charAnalysis->bestContours.size(); i++) { - if (charAnalysis->bestCharSegments[i] == false) - continue; + if (charAnalysis->bestCharSegments[i] == false) + continue; + Rect mr = boundingRect(charAnalysis->bestContours[i]); - Rect mr = boundingRect(charAnalysis->bestContours[i]); - - charWidths.push_back(mr.width); - charHeights.push_back(mr.height); + charWidths.push_back(mr.width); + charHeights.push_back(mr.height); } float avgCharWidth = median(charWidths.data(), charWidths.size()); @@ -122,56 +110,49 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con // Do the histogram analysis to figure out char regions - timespec startTime; getTime(&startTime); - vector allHistograms; vector allBoxes; for (int i = 0; i < charAnalysis->allContours.size(); i++) { - Mat histogramMask = Mat::zeros(charAnalysis->thresholds[i].size(), CV_8U); fillConvexPoly(histogramMask, charAnalysis->linePolygon.data(), charAnalysis->linePolygon.size(), Scalar(255,255,255)); - VerticalHistogram vertHistogram(charAnalysis->thresholds[i], histogramMask); - if (this->config->debugCharSegmenter) { - Mat histoCopy(vertHistogram.histoImg.size(), vertHistogram.histoImg.type()); - //vertHistogram.copyTo(histoCopy); - cvtColor(vertHistogram.histoImg, histoCopy, CV_GRAY2RGB); - allHistograms.push_back(histoCopy); + Mat histoCopy(vertHistogram.histoImg.size(), vertHistogram.histoImg.type()); + //vertHistogram.copyTo(histoCopy); + cvtColor(vertHistogram.histoImg, histoCopy, CV_GRAY2RGB); + allHistograms.push_back(histoCopy); } // float score = 0; vector charBoxes = getHistogramBoxes(vertHistogram, avgCharWidth, avgCharHeight, &score); - if (this->config->debugCharSegmenter) { - for (int cboxIdx = 0; cboxIdx < charBoxes.size(); cboxIdx++) - { - rectangle(allHistograms[i], charBoxes[cboxIdx], Scalar(0, 255, 0)); - } + for (int cboxIdx = 0; cboxIdx < charBoxes.size(); cboxIdx++) + { + rectangle(allHistograms[i], charBoxes[cboxIdx], Scalar(0, 255, 0)); + } - Mat histDashboard = drawImageDashboard(allHistograms, allHistograms[0].type(), 3); - displayImage(config, "Char seg histograms", histDashboard); + Mat histDashboard = drawImageDashboard(allHistograms, allHistograms[0].type(), 3); + displayImage(config, "Char seg histograms", histDashboard); } for (int z = 0; z < charBoxes.size(); z++) - allBoxes.push_back(charBoxes[z]); + allBoxes.push_back(charBoxes[z]); //drawAndWait(&histogramMask); } - float medianCharWidth = avgCharWidth; vector widthValues; // Compute largest char width @@ -182,7 +163,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con medianCharWidth = median(widthValues.data(), widthValues.size()); - if (config->debugTiming) { timespec endTime; @@ -193,25 +173,23 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con //ColorFilter colorFilter(img, charAnalysis->getCharacterMask()); vector candidateBoxes = getBestCharBoxes(charAnalysis->thresholds[0], allBoxes, medianCharWidth); - if (this->config->debugCharSegmenter) { - // Setup the dashboard images to show the cleaning filters + // Setup the dashboard images to show the cleaning filters for (int i = 0; i < charAnalysis->thresholds.size(); i++) { - Mat cleanImg = Mat::zeros(charAnalysis->thresholds[i].size(), charAnalysis->thresholds[i].type()); - Mat boxMask = getCharBoxMask(charAnalysis->thresholds[i], candidateBoxes); - charAnalysis->thresholds[i].copyTo(cleanImg); - bitwise_and(cleanImg, boxMask, cleanImg); - cvtColor(cleanImg, cleanImg, CV_GRAY2BGR); + Mat cleanImg = Mat::zeros(charAnalysis->thresholds[i].size(), charAnalysis->thresholds[i].type()); + Mat boxMask = getCharBoxMask(charAnalysis->thresholds[i], candidateBoxes); + charAnalysis->thresholds[i].copyTo(cleanImg); + bitwise_and(cleanImg, boxMask, cleanImg); + cvtColor(cleanImg, cleanImg, CV_GRAY2BGR); - for (int c = 0; c < candidateBoxes.size(); c++) - rectangle(cleanImg, candidateBoxes[c], Scalar(0, 255, 0), 1); - imgDbgCleanStages.push_back(cleanImg); + for (int c = 0; c < candidateBoxes.size(); c++) + rectangle(cleanImg, candidateBoxes[c], Scalar(0, 255, 0), 1); + imgDbgCleanStages.push_back(cleanImg); } } - getTime(&startTime); filterEdgeBoxes(charAnalysis->thresholds, candidateBoxes, medianCharWidth, avgCharHeight); @@ -238,7 +216,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con if (this->config->debugCharSegmenter) { - Mat imgDash = drawImageDashboard(charAnalysis->thresholds, CV_8U, 3); displayImage(config, "Segmentation after cleaning", imgDash); @@ -250,11 +227,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con } } - - - - - if (config->debugTiming) { timespec endTime; @@ -268,11 +240,6 @@ CharacterSegmenter::~CharacterSegmenter() delete charAnalysis; } - - - - - // Given a histogram and the horizontal line boundaries, respond with an array of boxes where the characters are // Scores the histogram quality as well based on num chars, char volume, and even separation vector CharacterSegmenter::getHistogramBoxes(VerticalHistogram histogram, float avgCharWidth, float avgCharHeight, float* score) @@ -298,8 +265,8 @@ vector CharacterSegmenter::getHistogramBoxes(VerticalHistogram histogram, } else if (allBoxes[i].width > avgCharWidth * 2 && allBoxes[i].width < MAX_SEGMENT_WIDTH * 2 && allBoxes[i].height > MIN_HISTOGRAM_HEIGHT) { - // rectangle(histogram.histoImg, allBoxes[i], Scalar(255, 0, 0) ); - // drawAndWait(&histogram.histoImg); + // rectangle(histogram.histoImg, allBoxes[i], Scalar(255, 0, 0) ); + // drawAndWait(&histogram.histoImg); // Try to split up doubles into two good char regions, check for a break between 40% and 60% int leftEdge = allBoxes[i].x + (int) (((float) allBoxes[i].width) * 0.4f); int rightEdge = allBoxes[i].x + (int) (((float) allBoxes[i].width) * 0.6f); @@ -314,29 +281,26 @@ vector CharacterSegmenter::getHistogramBoxes(VerticalHistogram histogram, if (maxHeightChar1 > MIN_HISTOGRAM_HEIGHT && minHeight < (0.25 * ((float) maxHeightChar1))) { - // Add a box for Char1 - Point botRight = Point(minX - 1, allBoxes[i].y + allBoxes[i].height); - charBoxes.push_back(Rect(allBoxes[i].tl(), botRight) ); + // Add a box for Char1 + Point botRight = Point(minX - 1, allBoxes[i].y + allBoxes[i].height); + charBoxes.push_back(Rect(allBoxes[i].tl(), botRight) ); } if (maxHeightChar2 > MIN_HISTOGRAM_HEIGHT && minHeight < (0.25 * ((float) maxHeightChar2))) { - // Add a box for Char2 - Point topLeft = Point(minX + 1, allBoxes[i].y); - charBoxes.push_back(Rect(topLeft, allBoxes[i].br()) ); + // Add a box for Char2 + Point topLeft = Point(minX + 1, allBoxes[i].y); + charBoxes.push_back(Rect(topLeft, allBoxes[i].br()) ); } } } - - return charBoxes; } vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxes, float avgCharWidth) { - float MAX_SEGMENT_WIDTH = avgCharWidth * 1.55; // This histogram is based on how many char boxes (from ALL of the many thresholded images) are covering each column @@ -344,7 +308,6 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe Mat histoImg = Mat::zeros(Size(img.cols, img.rows), CV_8U); - int columnCount; for (int col = 0; col < img.cols; col++) @@ -354,7 +317,7 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe for (int i = 0; i < charBoxes.size(); i++) { if (col >= charBoxes[i].x && col < (charBoxes[i].x + charBoxes[i].width)) - columnCount++; + columnCount++; } // Fill the line of the histogram @@ -370,7 +333,6 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe float bestRowScore = 0; vector bestBoxes; - for (int row = 0; row < histoImg.rows; row++) { vector validBoxes; @@ -387,48 +349,46 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe for (int boxidx = 0; boxidx < allBoxes.size(); boxidx++) { int w = allBoxes[boxidx].width; - if (w >= config->segmentationMinBoxWidthPx && w <= MAX_SEGMENT_WIDTH) - { - float widthDiffPixels = abs(w - avgCharWidth); - float widthDiffPercent = widthDiffPixels / avgCharWidth; - rowScore += 10 * (1 - widthDiffPercent); + if (w >= config->segmentationMinBoxWidthPx && w <= MAX_SEGMENT_WIDTH) + { + float widthDiffPixels = abs(w - avgCharWidth); + float widthDiffPercent = widthDiffPixels / avgCharWidth; + rowScore += 10 * (1 - widthDiffPercent); - if (widthDiffPercent < 0.25) // Bonus points when it's close to the average character width - rowScore += 8; + if (widthDiffPercent < 0.25) // Bonus points when it's close to the average character width + rowScore += 8; - validBoxes.push_back(allBoxes[boxidx]); - } - else if (w > avgCharWidth * 2 && w <= MAX_SEGMENT_WIDTH * 2 ) - { - // Try to split up doubles into two good char regions, check for a break between 40% and 60% - int leftEdge = allBoxes[boxidx].x + (int) (((float) allBoxes[boxidx].width) * 0.4f); - int rightEdge = allBoxes[boxidx].x + (int) (((float) allBoxes[boxidx].width) * 0.6f); + validBoxes.push_back(allBoxes[boxidx]); + } + else if (w > avgCharWidth * 2 && w <= MAX_SEGMENT_WIDTH * 2 ) + { + // Try to split up doubles into two good char regions, check for a break between 40% and 60% + int leftEdge = allBoxes[boxidx].x + (int) (((float) allBoxes[boxidx].width) * 0.4f); + int rightEdge = allBoxes[boxidx].x + (int) (((float) allBoxes[boxidx].width) * 0.6f); - int minX = histogram.getLocalMinimum(leftEdge, rightEdge); - int maxXChar1 = histogram.getLocalMaximum(allBoxes[boxidx].x, minX); - int maxXChar2 = histogram.getLocalMaximum(minX, allBoxes[boxidx].x + allBoxes[boxidx].width); - int minHeight = histogram.getHeightAt(minX); + int minX = histogram.getLocalMinimum(leftEdge, rightEdge); + int maxXChar1 = histogram.getLocalMaximum(allBoxes[boxidx].x, minX); + int maxXChar2 = histogram.getLocalMaximum(minX, allBoxes[boxidx].x + allBoxes[boxidx].width); + int minHeight = histogram.getHeightAt(minX); - int maxHeightChar1 = histogram.getHeightAt(maxXChar1); - int maxHeightChar2 = histogram.getHeightAt(maxXChar2); + int maxHeightChar1 = histogram.getHeightAt(maxXChar1); + int maxHeightChar2 = histogram.getHeightAt(maxXChar2); - if ( minHeight < (0.25 * ((float) maxHeightChar1))) - { - // Add a box for Char1 - Point botRight = Point(minX - 1, allBoxes[boxidx].y + allBoxes[boxidx].height); - validBoxes.push_back(Rect(allBoxes[boxidx].tl(), botRight) ); - } - if ( minHeight < (0.25 * ((float) maxHeightChar2))) - { - // Add a box for Char2 - Point topLeft = Point(minX + 1, allBoxes[boxidx].y); - validBoxes.push_back(Rect(topLeft, allBoxes[boxidx].br()) ); - } - } + if ( minHeight < (0.25 * ((float) maxHeightChar1))) + { + // Add a box for Char1 + Point botRight = Point(minX - 1, allBoxes[boxidx].y + allBoxes[boxidx].height); + validBoxes.push_back(Rect(allBoxes[boxidx].tl(), botRight) ); + } + if ( minHeight < (0.25 * ((float) maxHeightChar2))) + { + // Add a box for Char2 + Point topLeft = Point(minX + 1, allBoxes[boxidx].y); + validBoxes.push_back(Rect(topLeft, allBoxes[boxidx].br()) ); + } + } } - - if (rowScore > bestRowScore) { bestRowScore = rowScore; @@ -437,8 +397,6 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe } } - - if (this->config->debugCharSegmenter) { cvtColor(histoImg, histoImg, CV_GRAY2BGR); @@ -455,7 +413,6 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe } - return bestBoxes; } @@ -476,7 +433,7 @@ vector CharacterSegmenter::get1DHits(Mat img, int yOffset) } if ((isOn == false && onSegment == true) || - (col == img.cols - 1 && onSegment == true)) + (col == img.cols - 1 && onSegment == true)) { // A segment just ended or we're at the very end of the row and we're on a segment Point topLeft = Point(col - curSegmentLength, top.getPointAt(col - curSegmentLength) - 1); @@ -489,11 +446,9 @@ vector CharacterSegmenter::get1DHits(Mat img, int yOffset) } - return hits; } - void CharacterSegmenter::removeSmallContours(vector thresholds, vector > > allContours, float avgCharWidth, float avgCharHeight) { //const float MIN_CHAR_AREA = 0.02 * avgCharWidth * avgCharHeight; // To clear out the tiny specks @@ -505,14 +460,14 @@ void CharacterSegmenter::removeSmallContours(vector thresholds, vector CharacterSegmenter::combineCloseBoxes( vector charBoxes, floa { if (i == charBoxes.size() - 1) { - newCharBoxes.push_back(charBoxes[i]); - break; + newCharBoxes.push_back(charBoxes[i]); + break; } float bigWidth = (charBoxes[i + 1].x + charBoxes[i + 1].width - charBoxes[i].x); @@ -543,24 +498,22 @@ vector CharacterSegmenter::combineCloseBoxes( vector charBoxes, floa newCharBoxes.push_back(bigRect); if (this->config->debugCharSegmenter) { - for (int z = 0; z < charAnalysis->thresholds.size(); z++) - { - Point center(bigRect.x + bigRect.width / 2, bigRect.y + bigRect.height / 2); - RotatedRect rrect(center, Size2f(bigRect.width, bigRect.height + (bigRect.height / 2)), 0); - ellipse(imgDbgCleanStages[z], rrect, Scalar(0,255,0), 1); - } - cout << "Merging 2 boxes -- " << i << " and " << i + 1 << endl; + for (int z = 0; z < charAnalysis->thresholds.size(); z++) + { + Point center(bigRect.x + bigRect.width / 2, bigRect.y + bigRect.height / 2); + RotatedRect rrect(center, Size2f(bigRect.width, bigRect.height + (bigRect.height / 2)), 0); + ellipse(imgDbgCleanStages[z], rrect, Scalar(0,255,0), 1); + } + cout << "Merging 2 boxes -- " << i << " and " << i + 1 << endl; } i++; } else { - newCharBoxes.push_back(charBoxes[i]); + newCharBoxes.push_back(charBoxes[i]); } - - } return newCharBoxes; @@ -575,7 +528,6 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c Mat mask = getCharBoxMask(thresholds[0], charRegions); - for (int i = 0; i < thresholds.size(); i++) { bitwise_and(thresholds[i], mask, thresholds[i]); @@ -598,82 +550,74 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c const float MIN_SPECKLE_HEIGHT = ((float)charRegions[j].height) * MIN_SPECKLE_HEIGHT_PERCENT; const float MIN_CONTOUR_AREA = ((float)charRegions[j].area()) * MIN_CONTOUR_AREA_PERCENT; - int tallestContourHeight = 0; float totalArea = 0; for (int c = 0; c < contours.size(); c++) { - if (contours[c].size() == 0) - continue; - if (charRegions[j].contains(contours[c][0]) == false) - continue; + if (contours[c].size() == 0) + continue; + if (charRegions[j].contains(contours[c][0]) == false) + continue; + Rect r = boundingRect(contours[c]); + if (r.height <= MIN_SPECKLE_HEIGHT || r.width <= MIN_SPECKLE_WIDTH_PX) + { + // Erase this speckle + drawContours(thresholds[i], contours, c, Scalar(0,0,0), CV_FILLED); - Rect r = boundingRect(contours[c]); + if (this->config->debugCharSegmenter) + { + drawContours(imgDbgCleanStages[i], contours, c, COLOR_DEBUG_SPECKLES, CV_FILLED); + } + } + else + { + if (r.height > tallestContourHeight) + tallestContourHeight = r.height; - if (r.height <= MIN_SPECKLE_HEIGHT || r.width <= MIN_SPECKLE_WIDTH_PX) - { - // Erase this speckle - drawContours(thresholds[i], contours, c, Scalar(0,0,0), CV_FILLED); + totalArea += contourArea(contours[c]); - if (this->config->debugCharSegmenter) - { - drawContours(imgDbgCleanStages[i], contours, c, COLOR_DEBUG_SPECKLES, CV_FILLED); - } - } - else - { - if (r.height > tallestContourHeight) - tallestContourHeight = r.height; - - totalArea += contourArea(contours[c]); - - - } - //else if (r.height > tallestContourHeight) - //{ - // tallestContourIndex = c; - // tallestContourHeight = h; - //} + } + //else if (r.height > tallestContourHeight) + //{ + // tallestContourIndex = c; + // tallestContourHeight = h; + //} } - - if (totalArea < MIN_CONTOUR_AREA) { - // Character is not voluminous enough. Erase it. - if (this->config->debugCharSegmenter) - { - cout << "Character CLEAN: (area) removing box " << j << " in threshold " << i << " -- Area " << totalArea << " < " << MIN_CONTOUR_AREA << endl; + // Character is not voluminous enough. Erase it. + if (this->config->debugCharSegmenter) + { + cout << "Character CLEAN: (area) removing box " << j << " in threshold " << i << " -- Area " << totalArea << " < " << MIN_CONTOUR_AREA << endl; - Rect boxTop(charRegions[j].x, charRegions[j].y - 10, charRegions[j].width, 10); - rectangle(imgDbgCleanStages[i], boxTop, COLOR_DEBUG_MIN_AREA, -1); - } + Rect boxTop(charRegions[j].x, charRegions[j].y - 10, charRegions[j].width, 10); + rectangle(imgDbgCleanStages[i], boxTop, COLOR_DEBUG_MIN_AREA, -1); + } - - rectangle(thresholds[i], charRegions[j], Scalar(0, 0, 0), -1); + rectangle(thresholds[i], charRegions[j], Scalar(0, 0, 0), -1); } else if (tallestContourHeight < ((float) charRegions[j].height * MIN_CONTOUR_HEIGHT_PERCENT)) { - // This character is too short. Black the whole thing out - if (this->config->debugCharSegmenter) - { - cout << "Character CLEAN: (height) removing box " << j << " in threshold " << i << " -- Height " << tallestContourHeight << " < " << ((float) charRegions[j].height * MIN_CONTOUR_HEIGHT_PERCENT) << endl; + // This character is too short. Black the whole thing out + if (this->config->debugCharSegmenter) + { + cout << "Character CLEAN: (height) removing box " << j << " in threshold " << i << " -- Height " << tallestContourHeight << " < " << ((float) charRegions[j].height * MIN_CONTOUR_HEIGHT_PERCENT) << endl; - Rect boxBottom(charRegions[j].x, charRegions[j].y + charRegions[j].height, charRegions[j].width, 10); - rectangle(imgDbgCleanStages[i], boxBottom, COLOR_DEBUG_MIN_HEIGHT, -1); - } - rectangle(thresholds[i], charRegions[j], Scalar(0, 0, 0), -1); + Rect boxBottom(charRegions[j].x, charRegions[j].y + charRegions[j].height, charRegions[j].width, 10); + rectangle(imgDbgCleanStages[i], boxBottom, COLOR_DEBUG_MIN_HEIGHT, -1); + } + rectangle(thresholds[i], charRegions[j], Scalar(0, 0, 0), -1); } } - Mat closureElement = getStructuringElement( 1, - Size( 2 + 1, 2+1 ), - Point( 1, 1 ) ); + Size( 2 + 1, 2+1 ), + Point( 1, 1 ) ); //morphologyEx(thresholds[i], thresholds[i], MORPH_OPEN, element); @@ -685,14 +629,13 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c // Lastly, draw a clipping line between each character boxes for (int j = 0; j < charRegions.size(); j++) { - line(thresholds[i], Point(charRegions[j].x - 1, charRegions[j].y), Point(charRegions[j].x - 1, charRegions[j].y + charRegions[j].height), Scalar(0, 0, 0)); - line(thresholds[i], Point(charRegions[j].x + charRegions[j].width + 1, charRegions[j].y), Point(charRegions[j].x + charRegions[j].width + 1, charRegions[j].y + charRegions[j].height), Scalar(0, 0, 0)); + line(thresholds[i], Point(charRegions[j].x - 1, charRegions[j].y), Point(charRegions[j].x - 1, charRegions[j].y + charRegions[j].height), Scalar(0, 0, 0)); + line(thresholds[i], Point(charRegions[j].x + charRegions[j].width + 1, charRegions[j].y), Point(charRegions[j].x + charRegions[j].width + 1, charRegions[j].y + charRegions[j].height), Scalar(0, 0, 0)); } } } - void CharacterSegmenter::cleanBasedOnColor(vector thresholds, Mat colorMask, vector charRegions) { // If I knock out x% of the contour area from this thing (after applying the color filter) @@ -702,79 +645,75 @@ void CharacterSegmenter::cleanBasedOnColor(vector thresholds, Mat colorMask for (int i = 0; i < thresholds.size(); i++) { - for (int j = 0; j < charRegions.size(); j++) + for (int j = 0; j < charRegions.size(); j++) + { + + Mat boxChar = Mat::zeros(thresholds[i].size(), CV_8U); + rectangle(boxChar, charRegions[j], Scalar(255,255,255), CV_FILLED); + + bitwise_and(thresholds[i], boxChar, boxChar); + + float meanBefore = mean(boxChar, boxChar)[0]; + + Mat thresholdCopy(thresholds[i].size(), CV_8U); + bitwise_and(colorMask, boxChar, thresholdCopy); + + float meanAfter = mean(thresholdCopy, boxChar)[0]; + + if (meanAfter < meanBefore * (1-MIN_PERCENT_CHUNK_REMOVED)) { + rectangle(thresholds[i], charRegions[j], Scalar(0,0,0), CV_FILLED); - Mat boxChar = Mat::zeros(thresholds[i].size(), CV_8U); - rectangle(boxChar, charRegions[j], Scalar(255,255,255), CV_FILLED); - - bitwise_and(thresholds[i], boxChar, boxChar); - - - - float meanBefore = mean(boxChar, boxChar)[0]; - - Mat thresholdCopy(thresholds[i].size(), CV_8U); - bitwise_and(colorMask, boxChar, thresholdCopy); - - float meanAfter = mean(thresholdCopy, boxChar)[0]; - - if (meanAfter < meanBefore * (1-MIN_PERCENT_CHUNK_REMOVED)) - { - rectangle(thresholds[i], charRegions[j], Scalar(0,0,0), CV_FILLED); - - if (this->config->debugCharSegmenter) - { - //vector tmpDebug; - //Mat thresholdCopy2 = Mat::zeros(thresholds[i].size(), CV_8U); - //rectangle(thresholdCopy2, charRegions[j], Scalar(255,255,255), CV_FILLED); - //tmpDebug.push_back(addLabel(thresholdCopy2, "box Mask")); - //bitwise_and(thresholds[i], thresholdCopy2, thresholdCopy2); - //tmpDebug.push_back(addLabel(thresholdCopy2, "box Mask + Thresh")); - //bitwise_and(colorMask, thresholdCopy2, thresholdCopy2); - //tmpDebug.push_back(addLabel(thresholdCopy2, "box Mask + Thresh + Color")); + if (this->config->debugCharSegmenter) + { + //vector tmpDebug; + //Mat thresholdCopy2 = Mat::zeros(thresholds[i].size(), CV_8U); + //rectangle(thresholdCopy2, charRegions[j], Scalar(255,255,255), CV_FILLED); + //tmpDebug.push_back(addLabel(thresholdCopy2, "box Mask")); + //bitwise_and(thresholds[i], thresholdCopy2, thresholdCopy2); + //tmpDebug.push_back(addLabel(thresholdCopy2, "box Mask + Thresh")); + //bitwise_and(colorMask, thresholdCopy2, thresholdCopy2); + //tmpDebug.push_back(addLabel(thresholdCopy2, "box Mask + Thresh + Color")); // // Mat tmpytmp = addLabel(thresholdCopy2, "box Mask + Thresh + Color"); // Mat tmpx = drawImageDashboard(tmpDebug, tmpytmp.type(), 1); - //drawAndWait( &tmpx ); + //drawAndWait( &tmpx ); + cout << "Segmentation Filter Clean by Color: Removed Threshold " << i << " charregion " << j << endl; + cout << "Segmentation Filter Clean by Color: before=" << meanBefore << " after=" << meanAfter << endl; - cout << "Segmentation Filter Clean by Color: Removed Threshold " << i << " charregion " << j << endl; - cout << "Segmentation Filter Clean by Color: before=" << meanBefore << " after=" << meanAfter << endl; - - Point topLeft(charRegions[j].x, charRegions[j].y); - circle(imgDbgCleanStages[i], topLeft, 5, COLOR_DEBUG_COLORFILTER, CV_FILLED); - } - } + Point topLeft(charRegions[j].x, charRegions[j].y); + circle(imgDbgCleanStages[i], topLeft, 5, COLOR_DEBUG_COLORFILTER, CV_FILLED); + } } + } } } - void CharacterSegmenter::cleanMostlyFullBoxes(vector thresholds, const vector charRegions) { float MAX_FILLED = 0.95 * 255; for (int i = 0; i < charRegions.size(); i++) { - Mat mask = Mat::zeros(thresholds[0].size(), CV_8U); - rectangle(mask, charRegions[i], Scalar(255,255,255), -1); + Mat mask = Mat::zeros(thresholds[0].size(), CV_8U); + rectangle(mask, charRegions[i], Scalar(255,255,255), -1); - for (int j = 0; j < thresholds.size(); j++) + for (int j = 0; j < thresholds.size(); j++) + { + if (mean(thresholds[j], mask)[0] > MAX_FILLED) { - if (mean(thresholds[j], mask)[0] > MAX_FILLED) - { - // Empty the rect - rectangle(thresholds[j], charRegions[i], Scalar(0,0,0), -1); + // Empty the rect + rectangle(thresholds[j], charRegions[i], Scalar(0,0,0), -1); - if (this->config->debugCharSegmenter) - { - Rect inset(charRegions[i].x + 2, charRegions[i].y - 2, charRegions[i].width - 4, charRegions[i].height - 4); - rectangle(imgDbgCleanStages[j], inset, COLOR_DEBUG_FULLBOX, 1); - } - } + if (this->config->debugCharSegmenter) + { + Rect inset(charRegions[i].x + 2, charRegions[i].y - 2, charRegions[i].width - 4, charRegions[i].height - 4); + rectangle(imgDbgCleanStages[j], inset, COLOR_DEBUG_FULLBOX, 1); + } } + } } } vector CharacterSegmenter::filterMostlyEmptyBoxes(vector thresholds, const vector charRegions) @@ -811,31 +750,29 @@ vector CharacterSegmenter::filterMostlyEmptyBoxes(vector thresholds, vector allPointsInBox; for (int c = 0; c < contours.size(); c++) { - if (contours[c].size() == 0) - continue; + if (contours[c].size() == 0) + continue; - for (int z = 0; z < contours[c].size(); z++) - allPointsInBox.push_back(contours[c][z]); + for (int z = 0; z < contours[c].size(); z++) + allPointsInBox.push_back(contours[c][z]); } float height = 0; if (allPointsInBox.size() > 0) { - height = boundingRect(allPointsInBox).height; + height = boundingRect(allPointsInBox).height; } - if (height >= ((float) charRegions[j].height * MIN_CONTOUR_HEIGHT_PERCENT)) { - boxScores[j] = boxScores[j] + 1; + boxScores[j] = boxScores[j] + 1; } else if (this->config->debugCharSegmenter) { - drawX(imgDbgCleanStages[i], charRegions[j], COLOR_DEBUG_EMPTYFILTER, 3); + drawX(imgDbgCleanStages[i], charRegions[j], COLOR_DEBUG_EMPTYFILTER, 3); } - } } @@ -862,16 +799,16 @@ vector CharacterSegmenter::filterMostlyEmptyBoxes(vector thresholds, // Erase the box from the Mat... mainly for debug purposes if (this->config->debugCharSegmenter) { - cout << "Mostly Empty Filter: box index: " << i; - cout << " this box had a score of : " << boxScores[i];; - cout << " MIN_FULL_BOXES: " << MIN_FULL_BOXES << endl;; + cout << "Mostly Empty Filter: box index: " << i; + cout << " this box had a score of : " << boxScores[i];; + cout << " MIN_FULL_BOXES: " << MIN_FULL_BOXES << endl;; - for (int z = 0; z < thresholds.size(); z++) - { - rectangle(thresholds[z], charRegions[i], Scalar(0,0,0), -1); + for (int z = 0; z < thresholds.size(); z++) + { + rectangle(thresholds[z], charRegions[i], Scalar(0,0,0), -1); - drawX(imgDbgCleanStages[z], charRegions[i], COLOR_DEBUG_EMPTYFILTER, 1); - } + drawX(imgDbgCleanStages[z], charRegions[i], COLOR_DEBUG_EMPTYFILTER, 1); + } } } @@ -902,7 +839,6 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector 0 && charBoxes[0].width < MIN_SEGMENT_WIDTH_EDGES) // charBoxes.erase(charBoxes.begin() + 0); - // TECHNIQUE #1 // Check for long vertical lines. Once the line is too long, mask the whole region @@ -934,7 +870,7 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector thresholds, const vector MIN_CONNECTED_EDGE_PIXELS) { - leftEdgeX = col; - break; + leftEdgeX = col; + break; } col--; @@ -963,13 +899,12 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector MIN_CONNECTED_EDGE_PIXELS) { - rightEdgeX = col; - break; + rightEdgeX = col; + break; } col++; } - if (leftEdgeX != 0) leftEdges.push_back(leftEdgeX); if (rightEdgeX != thresholds[i].cols) @@ -1007,7 +942,6 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector thresholds, const vector MAX_COVERAGE_PERCENT) || - (charRegions[0].width - leftCoveragePx < config->segmentationMinBoxWidthPx)) + (charRegions[0].width - leftCoveragePx < config->segmentationMinBoxWidthPx)) { rectangle(mask, charRegions[0], Scalar(0,0,0), -1); // Mask the whole region if (this->config->debugCharSegmenter) - cout << "Edge Filter: Entire left region is erased" << endl; + cout << "Edge Filter: Entire left region is erased" << endl; } if ((rightCoveragePercent > MAX_COVERAGE_PERCENT) || - (charRegions[charRegions.size() -1].width - rightCoveragePx < config->segmentationMinBoxWidthPx)) + (charRegions[charRegions.size() -1].width - rightCoveragePx < config->segmentationMinBoxWidthPx)) { rectangle(mask, charRegions[charRegions.size() -1], Scalar(0,0,0), -1); if (this->config->debugCharSegmenter) - cout << "Edge Filter: Entire right region is erased" << endl; + cout << "Edge Filter: Entire right region is erased" << endl; } for (int i = 0; i < thresholds.size(); i++) @@ -1034,7 +968,6 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vectorconfig->debugCharSegmenter) { cout << "Edge Filter: left=" << leftEdge << " right=" << rightEdge << endl; @@ -1044,7 +977,7 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector thresholds, const vector > contours; - Mat mask = Mat::zeros(thresholds[i].size(),CV_8U); - rectangle(mask, charRegions[boxidx], Scalar(255,255,255), CV_FILLED); + vector > contours; + Mat mask = Mat::zeros(thresholds[i].size(),CV_8U); + rectangle(mask, charRegions[boxidx], Scalar(255,255,255), CV_FILLED); - bitwise_and(thresholds[i], mask, mask); - findContours(mask, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); - //int tallContourIndex = isSkinnyLineInsideBox(thresholds[i], charRegions[boxidx], allContours[i], hierarchy[i], avgCharWidth, avgCharHeight); - float tallestContourHeight = 0; - float fattestContourWidth = 0; - float biggestContourArea = 0; - for (int c = 0; c < contours.size(); c++) - { - Rect r = boundingRect(contours[c]); - if (r.height > tallestContourHeight) - tallestContourHeight = r.height; - if (r.width > fattestContourWidth) - fattestContourWidth = r.width; - float a = r.area(); - if (a > biggestContourArea) - biggestContourArea = a; - } + bitwise_and(thresholds[i], mask, mask); + findContours(mask, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); + //int tallContourIndex = isSkinnyLineInsideBox(thresholds[i], charRegions[boxidx], allContours[i], hierarchy[i], avgCharWidth, avgCharHeight); + float tallestContourHeight = 0; + float fattestContourWidth = 0; + float biggestContourArea = 0; + for (int c = 0; c < contours.size(); c++) + { + Rect r = boundingRect(contours[c]); + if (r.height > tallestContourHeight) + tallestContourHeight = r.height; + if (r.width > fattestContourWidth) + fattestContourWidth = r.width; + float a = r.area(); + if (a > biggestContourArea) + biggestContourArea = a; + } - float minArea = charRegions[boxidx].area() * MIN_EDGE_CONTOUR_AREA_PCT; - if ((fattestContourWidth < MIN_BOX_WIDTH_PX) || - (tallestContourHeight < MIN_EDGE_CONTOUR_HEIGHT) || - (biggestContourArea < minArea) - ) - { - // Find a good place to MASK this contour. - // for now, just mask the whole thing - if (this->debug) - { + float minArea = charRegions[boxidx].area() * MIN_EDGE_CONTOUR_AREA_PCT; + if ((fattestContourWidth < MIN_BOX_WIDTH_PX) || + (tallestContourHeight < MIN_EDGE_CONTOUR_HEIGHT) || + (biggestContourArea < minArea) + ) + { + // Find a good place to MASK this contour. + // for now, just mask the whole thing + if (this->debug) + { - rectangle(imgDbgCleanStages[i], charRegions[boxidx], COLOR_DEBUG_EDGE, 2); - cout << "Edge Filter: threshold " << i << " box " << boxidx << endl; - } - rectangle(thresholds[i], charRegions[boxidx], Scalar(0,0,0), -1); - } - else - { - filteredCharRegions.push_back(charRegions[boxidx]); - } + rectangle(imgDbgCleanStages[i], charRegions[boxidx], COLOR_DEBUG_EDGE, 2); + cout << "Edge Filter: threshold " << i << " box " << boxidx << endl; + } + rectangle(thresholds[i], charRegions[boxidx], Scalar(0,0,0), -1); + } + else + { + filteredCharRegions.push_back(charRegions[boxidx]); + } } } */ @@ -1140,7 +1073,7 @@ int CharacterSegmenter::getLongestBlobLengthBetweenLines(Mat img, int col) // Add a little extra to the score if this is outside of the lines if (!isbetweenLines) - incrementBy = 1.1; + incrementBy = 1.1; onSegment = true; curSegmentLength += incrementBy; @@ -1151,10 +1084,10 @@ int CharacterSegmenter::getLongestBlobLengthBetweenLines(Mat img, int col) } if ((isOn == false && onSegment == true) || - (row == img.rows - 1 && onSegment == true)) + (row == img.rows - 1 && onSegment == true)) { if (wasbetweenLines && curSegmentLength > longestBlobLength) - longestBlobLength = curSegmentLength; + longestBlobLength = curSegmentLength; onSegment = false; isbetweenLines = false; @@ -1163,7 +1096,6 @@ int CharacterSegmenter::getLongestBlobLengthBetweenLines(Mat img, int col) } - return longestBlobLength; } @@ -1183,7 +1115,6 @@ int CharacterSegmenter::isSkinnyLineInsideBox(Mat threshold, Rect box, vector tallestContourHeight) { - tallestContourIdx = s; - tallestContourHeight = r.height; - tallestContourWidth = r.width; - tallestContourArea = contourArea(subContours[s]); + tallestContourIdx = s; + tallestContourHeight = r.height; + tallestContourWidth = r.width; + tallestContourArea = contourArea(subContours[s]); } } if (tallestContourIdx != -1) { - //cout << "Edge Filter: " << tallestContourHeight << " -- " << avgCharHeight << endl; if (tallestContourHeight >= avgCharHeight * 0.9 && - ((tallestContourWidth < config->segmentationMinBoxWidthPx) || (tallestContourArea < avgCharWidth * avgCharHeight * 0.1))) + ((tallestContourWidth < config->segmentationMinBoxWidthPx) || (tallestContourArea < avgCharWidth * avgCharHeight * 0.1))) { - cout << "Edge Filter: Avg contour width: " << avgCharWidth << " This guy is: " << tallestContourWidth << endl; - cout << "Edge Filter: tallestContourArea: " << tallestContourArea << " Minimum: " << avgCharWidth * avgCharHeight * 0.1 << endl; - return i; + cout << "Edge Filter: Avg contour width: " << avgCharWidth << " This guy is: " << tallestContourWidth << endl; + cout << "Edge Filter: tallestContourArea: " << tallestContourArea << " Minimum: " << avgCharWidth * avgCharHeight * 0.1 << endl; + return i; } } } @@ -1230,14 +1160,12 @@ int CharacterSegmenter::isSkinnyLineInsideBox(Mat threshold, Rect box, vector charBoxes) { Mat mask = Mat::zeros(img_threshold.size(), CV_8U); for (int i = 0; i < charBoxes.size(); i++) - rectangle(mask, charBoxes[i], Scalar(255, 255, 255), -1); + rectangle(mask, charBoxes[i], Scalar(255, 255, 255), -1); return mask; } diff --git a/src/openalpr/cjson.h b/src/openalpr/cjson.h index 9bfc54f..4703a6d 100644 --- a/src/openalpr/cjson.h +++ b/src/openalpr/cjson.h @@ -24,8 +24,7 @@ #define cJSON__h #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif /* cJSON Types: */ @@ -40,22 +39,24 @@ extern "C" #define cJSON_IsReference 256 /* The cJSON structure: */ -typedef struct cJSON { - struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ - struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ +typedef struct cJSON +{ + struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ - int type; /* The type of the item, as above. */ + int type; /* The type of the item, as above. */ - char *valuestring; /* The item's string, if type==cJSON_String */ - int valueint; /* The item's number, if type==cJSON_Number */ - double valuedouble; /* The item's number, if type==cJSON_Number */ + char *valuestring; /* The item's string, if type==cJSON_String */ + int valueint; /* The item's number, if type==cJSON_Number */ + double valuedouble; /* The item's number, if type==cJSON_Number */ - char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ } cJSON; -typedef struct cJSON_Hooks { - void *(*malloc_fn)(size_t sz); - void (*free_fn)(void *ptr); +typedef struct cJSON_Hooks +{ + void *(*malloc_fn)(size_t sz); + void (*free_fn)(void *ptr); } cJSON_Hooks; /* Supply malloc, realloc and free functions to cJSON */ diff --git a/src/openalpr/colorfilter.cpp b/src/openalpr/colorfilter.cpp index cc20bfa..5be932e 100644 --- a/src/openalpr/colorfilter.cpp +++ b/src/openalpr/colorfilter.cpp @@ -17,11 +17,8 @@ * along with this program. If not, see . */ - #include "colorfilter.h" - - ColorFilter::ColorFilter(Mat image, Mat characterMask, Config* config) { @@ -32,7 +29,6 @@ ColorFilter::ColorFilter(Mat image, Mat characterMask, Config* config) this->debug = config->debugColorFiler; - this->grayscale = imageIsGrayscale(image); if (this->debug) @@ -48,7 +44,6 @@ ColorFilter::ColorFilter(Mat image, Mat characterMask, Config* config) findCharColors(); - if (config->debugTiming) { timespec endTime; @@ -75,12 +70,12 @@ bool ColorFilter::imageIsGrayscale(Mat image) if (r == g == b) { - // So far so good + // So far so good } else { - // Image is color. - return false; + // Image is color. + return false; } } } @@ -112,16 +107,14 @@ void ColorFilter::findCharColors() Mat erodedCharMask(charMask.size(), CV_8U); Mat element = getStructuringElement( 1, - Size( 2 + 1, 2+1 ), - Point( 1, 1 ) ); + Size( 2 + 1, 2+1 ), + Point( 1, 1 ) ); erode(charMask, erodedCharMask, element); vector > contours; vector hierarchy; findContours(erodedCharMask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE); - - vector hMeans, sMeans, vMeans; vector hStdDevs, sStdDevs, vStdDevs; @@ -130,50 +123,46 @@ void ColorFilter::findCharColors() if (hierarchy[i][3] != -1) continue; - Mat singleCharMask = Mat::zeros(hsv.size(), CV_8U); + Mat singleCharMask = Mat::zeros(hsv.size(), CV_8U); - drawContours(singleCharMask, contours, - i, // draw this contour - cv::Scalar(255,255,255), // in - CV_FILLED, - 8, - hierarchy - ); + drawContours(singleCharMask, contours, + i, // draw this contour + cv::Scalar(255,255,255), // in + CV_FILLED, + 8, + hierarchy + ); - // get rid of the outline by drawing a 1 pixel width black line - drawContours(singleCharMask, contours, - i, // draw this contour - cv::Scalar(0,0,0), // in - 1, - 8, - hierarchy - ); + // get rid of the outline by drawing a 1 pixel width black line + drawContours(singleCharMask, contours, + i, // draw this contour + cv::Scalar(0,0,0), // in + 1, + 8, + hierarchy + ); + //drawAndWait(&singleCharMask); + Scalar mean; + Scalar stddev; + meanStdDev(hsv, mean, stddev, singleCharMask); + if (this->debug) + { + cout << "ColorFilter " << setw(3) << i << ". Mean: h: " << setw(7) << mean[0] << " s: " << setw(7) <debug) - { - cout << "ColorFilter " << setw(3) << i << ". Mean: h: " << setw(7) << mean[0] << " s: " << setw(7) <getMajorityOpinion(sMeans, .65, 35); int bestValIndex = this->getMajorityOpinion(vMeans, .65, 30); - if (sMeans[bestSatIndex] < MINIMUM_SATURATION) return; - bool doHueFilter = false, doSatFilter = false, doValFilter = false; float hueMin, hueMax; float satMin, satMax; @@ -259,8 +246,6 @@ void ColorFilter::findCharColors() cout << "ColorFilter Val: " << bestValIndex << " : " << setw(7) << vMeans[bestValIndex] << " -- " << valMin << "-" << valMax << endl; } - - Mat imgDebugHueOnly = Mat::zeros(hsv.size(), hsv.type()); Mat imgDebug = Mat::zeros(hsv.size(), hsv.type()); Mat imgDistanceFromCenter = Mat::zeros(hsv.size(), CV_8U); @@ -291,19 +276,19 @@ void ColorFilter::findCharColors() if (doHueFilter && (h < hueMin || h > hueMax)) { - hPasses = false; - imgDebug.at(row, col)[0] = 0; - debugMask.at(row, col) = 0; + hPasses = false; + imgDebug.at(row, col)[0] = 0; + debugMask.at(row, col) = 0; } if (doSatFilter && (s < satMin || s > satMax)) { - sPasses = false; - imgDebug.at(row, col)[1] = 0; + sPasses = false; + imgDebug.at(row, col)[1] = 0; } if (doValFilter && (v < valMin || v > valMax)) { - vPasses = false; - imgDebug.at(row, col)[2] = 0; + vPasses = false; + imgDebug.at(row, col)[2] = 0; } //if (pixelPasses) @@ -314,27 +299,24 @@ void ColorFilter::findCharColors() //imgDebug.at(row, col)[2] = vPasses & 255; if ((hPasses) || (hPasses && sPasses))//(hPasses && vPasses) || (sPasses && vPasses) || - this->colorMask.at(row, col) = 255; + this->colorMask.at(row, col) = 255; else - this->colorMask.at(row, col) = 0; - + this->colorMask.at(row, col) = 0; if ((hPasses && sPasses) || (hPasses && vPasses) || (sPasses && vPasses)) { - vDistance = pow(vDistance, 0.9); + vDistance = pow(vDistance, 0.9); } else { - vDistance = pow(vDistance, 1.1); + vDistance = pow(vDistance, 1.1); } if (vDistance > 255) - vDistance = 255; + vDistance = 255; imgDistanceFromCenter.at(row, col) = vDistance; } } - - vector debugImagesSet; if (this->debug) @@ -346,14 +328,13 @@ void ColorFilter::findCharColors() debugImagesSet.push_back(addLabel(maskCopy, "color Mask Before")); } - Mat bigElement = getStructuringElement( 1, - Size( 3 + 1, 3+1 ), - Point( 1, 1 ) ); + Size( 3 + 1, 3+1 ), + Point( 1, 1 ) ); Mat smallElement = getStructuringElement( 1, - Size( 1 + 1, 1+1 ), - Point( 1, 1 ) ); + Size( 1 + 1, 1+1 ), + Point( 1, 1 ) ); morphologyEx(this->colorMask, this->colorMask, MORPH_CLOSE, bigElement); //dilate(this->colorMask, this->colorMask, bigElement); @@ -378,15 +359,12 @@ void ColorFilter::findCharColors() debugImagesSet.push_back(addLabel(debugMask, "COLOR Hues off")); - Mat dashboard = drawImageDashboard(debugImagesSet, imgDebugHueOnly.type(), 3); displayImage(config, "Color Filter Images", dashboard); } } - - // Goes through an array of values, picks the winner based on the highest percentage of other values that are within the maxValDifference // Return -1 if it fails. int ColorFilter::getMajorityOpinion(vector values, float minPercentAgreement, float maxValDifference) @@ -403,7 +381,7 @@ int ColorFilter::getMajorityOpinion(vector values, float minPercentAgreem { float diff = abs(values[i] - values[j]); if (diff < maxValDifference) - valuesInRange++; + valuesInRange++; overallDiff += diff; } diff --git a/src/openalpr/config.cpp b/src/openalpr/config.cpp index 46c8df8..f57c42f 100644 --- a/src/openalpr/config.cpp +++ b/src/openalpr/config.cpp @@ -19,7 +19,6 @@ #include "config.h" - Config::Config(const std::string country, const std::string runtimeBaseDir) { this->runtimeBaseDir = runtimeBaseDir; @@ -30,7 +29,7 @@ Config::Config(const std::string country, const std::string runtimeBaseDir) envRuntimeDir = getenv (ENV_VARIABLE_RUNTIME_DIR); if (runtimeBaseDir.compare("") != 0) { - // User has supplied a runtime directory. Use that. + // User has supplied a runtime directory. Use that. } else if (envRuntimeDir!=NULL) @@ -93,12 +92,10 @@ void Config::loadValues(string country) ocrImageWidthPx = round(((float) templateWidthPx) * ocrImagePercent); ocrImageHeightPx = round(((float)templateHeightPx) * ocrImagePercent); - float stateIdImagePercent = getFloat("common", "state_id_img_size_percent", 100); stateIdImageWidthPx = round(((float)templateWidthPx) * ocrImagePercent); stateIdimageHeightPx = round(((float)templateHeightPx) * ocrImagePercent); - charAnalysisMinPercent = getFloat(country, "char_analysis_min_pct", 0); charAnalysisHeightRange = getFloat(country, "char_analysis_height_range", 0); charAnalysisHeightStepSize = getFloat(country, "char_analysis_height_step_size", 0); @@ -150,7 +147,6 @@ void Config::debugOff() debugPostProcess = false; } - string Config::getCascadeRuntimeDir() { return this->runtimeBaseDir + CASCADE_DIR; @@ -168,9 +164,6 @@ string Config::getTessdataPrefix() return "TESSDATA_PREFIX=" + this->runtimeBaseDir + "/ocr/"; } - - - float Config::getFloat(string section, string key, float defaultValue) { const char * pszValue = ini->GetValue(section.c_str(), key.c_str(), NULL /*default*/); diff --git a/src/openalpr/config.h b/src/openalpr/config.h index a1f259c..78e6b7e 100644 --- a/src/openalpr/config.h +++ b/src/openalpr/config.h @@ -110,7 +110,7 @@ class Config string getPostProcessRuntimeDir(); string getTessdataPrefix(); -private: + private: CSimpleIniA* ini; string runtimeBaseDir; diff --git a/src/openalpr/constants.h b/src/openalpr/constants.h index 8c9f35c..f749a05 100644 --- a/src/openalpr/constants.h +++ b/src/openalpr/constants.h @@ -23,7 +23,7 @@ #define POSTPROCESS_DIR "/postprocess" #ifndef DEFAULT_RUNTIME_DIR - #define DEFAULT_RUNTIME_DIR "/default_runtime_data_dir/" +#define DEFAULT_RUNTIME_DIR "/default_runtime_data_dir/" #endif #define ENV_VARIABLE_RUNTIME_DIR "OPENALPR_RUNTIME_DIR" diff --git a/src/openalpr/featurematcher.cpp b/src/openalpr/featurematcher.cpp index d04e536..0540262 100644 --- a/src/openalpr/featurematcher.cpp +++ b/src/openalpr/featurematcher.cpp @@ -17,15 +17,12 @@ * along with this program. If not, see . */ - #include "featurematcher.h" - //const int DEFAULT_QUERY_FEATURES = 305; //const int DEFAULT_TRAINING_FEATURES = 305; const float MAX_DISTANCE_TO_MATCH = 100.0f; - FeatureMatcher::FeatureMatcher(Config* config) { this->config = config; @@ -35,7 +32,6 @@ FeatureMatcher::FeatureMatcher(Config* config) //this->descriptorMatcher = DescriptorMatcher::create( "FlannBased" ); - this->detector = new FastFeatureDetector(10, true); this->extractor = new BRISK(10, 1, 0.9); } @@ -52,114 +48,103 @@ FeatureMatcher::~FeatureMatcher() } - bool FeatureMatcher::isLoaded() { - if( detector.empty() || extractor.empty() || descriptorMatcher.empty() ) - { - return false; - } + if( detector.empty() || extractor.empty() || descriptorMatcher.empty() ) + { + return false; + } - return true; + return true; } int FeatureMatcher::numTrainingElements() { - return billMapping.size(); + return billMapping.size(); } - - - void FeatureMatcher::surfStyleMatching( const Mat& queryDescriptors, vector queryKeypoints, - vector& matches12 ) + vector& matches12 ) { - vector > matchesKnn; + vector > matchesKnn; - this->descriptorMatcher->radiusMatch(queryDescriptors, matchesKnn, MAX_DISTANCE_TO_MATCH); + this->descriptorMatcher->radiusMatch(queryDescriptors, matchesKnn, MAX_DISTANCE_TO_MATCH); + vector tempMatches; + _surfStyleMatching(queryDescriptors, matchesKnn, tempMatches); - vector tempMatches; - _surfStyleMatching(queryDescriptors, matchesKnn, tempMatches); - - crisscrossFiltering(queryKeypoints, tempMatches, matches12); + crisscrossFiltering(queryKeypoints, tempMatches, matches12); } - - void FeatureMatcher::_surfStyleMatching(const Mat& queryDescriptors, vector > matchesKnn, vector& matches12) { - //objectMatches.clear(); - //objectMatches.resize(objectIds.size()); - //cout << "starting matcher" << matchesKnn.size() << endl; - for (int descInd = 0; descInd < queryDescriptors.rows; descInd++) + //objectMatches.clear(); + //objectMatches.resize(objectIds.size()); + //cout << "starting matcher" << matchesKnn.size() << endl; + for (int descInd = 0; descInd < queryDescriptors.rows; descInd++) + { + const std::vector & matches = matchesKnn[descInd]; + //cout << "two: " << descInd << ":" << matches.size() << endl; + + // Check to make sure we have 2 matches. I think this is always the case, but it doesn't hurt to be sure + if (matchesKnn[descInd].size() > 1) + { + + // Next throw out matches with a crappy score + // Ignore... already handled by the radiusMatch + //if (matchesKnn[descInd][0].distance < MAX_DISTANCE_TO_MATCH) + //{ + float ratioThreshold = 0.75; + + // Check if both matches came from the same image. If they both came from the same image, score them slightly less harshly + if (matchesKnn[descInd][0].imgIdx == matchesKnn[descInd][1].imgIdx) { - const std::vector & matches = matchesKnn[descInd]; - //cout << "two: " << descInd << ":" << matches.size() << endl; - - // Check to make sure we have 2 matches. I think this is always the case, but it doesn't hurt to be sure - if (matchesKnn[descInd].size() > 1) - { - - // Next throw out matches with a crappy score - // Ignore... already handled by the radiusMatch - //if (matchesKnn[descInd][0].distance < MAX_DISTANCE_TO_MATCH) - //{ - float ratioThreshold = 0.75; - - // Check if both matches came from the same image. If they both came from the same image, score them slightly less harshly - if (matchesKnn[descInd][0].imgIdx == matchesKnn[descInd][1].imgIdx) - { - ratioThreshold = 0.85; - } - - if ((matchesKnn[descInd][0].distance / matchesKnn[descInd][1].distance) < ratioThreshold) - { - bool already_exists = false; - // Quickly run through the matches we've already added and make sure it's not a duplicate... - for (int q = 0; q < matches12.size(); q++) - { - if (matchesKnn[descInd][0].queryIdx == matches12[q].queryIdx) - { - already_exists = true; - break; - } - else if ((matchesKnn[descInd][0].trainIdx == matches12[q].trainIdx) && - (matchesKnn[descInd][0].imgIdx == matches12[q].imgIdx)) - { - already_exists = true; - break; - } - } - - // Good match. - if (already_exists == false) - matches12.push_back(matchesKnn[descInd][0]); - } - - - //} - } - else if (matchesKnn[descInd].size() == 1) - { - // Only match? Does this ever happen? - matches12.push_back(matchesKnn[descInd][0]); - } - // In the ratio test, we will compare the quality of a match with the next match that is not from the same object: - // we can accept several matches with similar scores as long as they are for the same object. Those should not be - // part of the model anyway as they are not discriminative enough - - //for (unsigned int first_index = 0; first_index < matches.size(); ++first_index) - //{ - - //matches12.push_back(match); - //} - - + ratioThreshold = 0.85; } + if ((matchesKnn[descInd][0].distance / matchesKnn[descInd][1].distance) < ratioThreshold) + { + bool already_exists = false; + // Quickly run through the matches we've already added and make sure it's not a duplicate... + for (int q = 0; q < matches12.size(); q++) + { + if (matchesKnn[descInd][0].queryIdx == matches12[q].queryIdx) + { + already_exists = true; + break; + } + else if ((matchesKnn[descInd][0].trainIdx == matches12[q].trainIdx) && + (matchesKnn[descInd][0].imgIdx == matches12[q].imgIdx)) + { + already_exists = true; + break; + } + } + // Good match. + if (already_exists == false) + matches12.push_back(matchesKnn[descInd][0]); + } + + //} + } + else if (matchesKnn[descInd].size() == 1) + { + // Only match? Does this ever happen? + matches12.push_back(matchesKnn[descInd][0]); + } + // In the ratio test, we will compare the quality of a match with the next match that is not from the same object: + // we can accept several matches with similar scores as long as they are for the same object. Those should not be + // part of the model anyway as they are not discriminative enough + + //for (unsigned int first_index = 0; first_index < matches.size(); ++first_index) + //{ + + //matches12.push_back(match); + //} + + } } @@ -176,8 +161,8 @@ void FeatureMatcher::crisscrossFiltering(const vector queryKeypoints, vector matchesForOnePlate; for (int j = 0; j < inputMatches.size(); j++) { - if (inputMatches[j].imgIdx == i) - matchesForOnePlate.push_back(inputMatches[j]); + if (inputMatches[j].imgIdx == i) + matchesForOnePlate.push_back(inputMatches[j]); } // For each plate, compare the lines for the keypoints (training image and query image) @@ -196,8 +181,6 @@ void FeatureMatcher::crisscrossFiltering(const vector queryKeypoints, matchIdx.push_back(j); } - - // Iterate through each line (n^2) removing the one with the most criss-crosses until there are none left. int mostIntersections = 1; while (mostIntersections > 0 && vlines.size() > 0) @@ -207,37 +190,37 @@ void FeatureMatcher::crisscrossFiltering(const vector queryKeypoints, for (int j = 0; j < vlines.size(); j++) { - int intrCount = 0; - for (int q = 0; q < vlines.size(); q++) - { - Point vintr = vlines[j].intersection(vlines[q]); - Point hintr = hlines[j].intersection(hlines[q]); - float vangleDiff = abs(vlines[j].angle - vlines[q].angle); - float hangleDiff = abs(hlines[j].angle - hlines[q].angle); - if (vintr.inside(crissCrossAreaVertical) && vangleDiff > 10) - { - intrCount++; - } - else if (hintr.inside(crissCrossAreaHorizontal) && hangleDiff > 10) - { - intrCount++; - } - } + int intrCount = 0; + for (int q = 0; q < vlines.size(); q++) + { + Point vintr = vlines[j].intersection(vlines[q]); + Point hintr = hlines[j].intersection(hlines[q]); + float vangleDiff = abs(vlines[j].angle - vlines[q].angle); + float hangleDiff = abs(hlines[j].angle - hlines[q].angle); + if (vintr.inside(crissCrossAreaVertical) && vangleDiff > 10) + { + intrCount++; + } + else if (hintr.inside(crissCrossAreaHorizontal) && hangleDiff > 10) + { + intrCount++; + } + } - if (intrCount > mostIntersections) - { - mostIntersections = intrCount; - mostIntersectionsIndex = j; - } + if (intrCount > mostIntersections) + { + mostIntersections = intrCount; + mostIntersectionsIndex = j; + } } if (mostIntersectionsIndex >= 0) { - if (this->config->debugStateId) - cout << "Filtered intersection! " << billMapping[i] << endl; - vlines.erase(vlines.begin() + mostIntersectionsIndex); - hlines.erase(hlines.begin() + mostIntersectionsIndex); - matchIdx.erase(matchIdx.begin() + mostIntersectionsIndex); + if (this->config->debugStateId) + cout << "Filtered intersection! " << billMapping[i] << endl; + vlines.erase(vlines.begin() + mostIntersectionsIndex); + hlines.erase(hlines.begin() + mostIntersectionsIndex); + matchIdx.erase(matchIdx.begin() + mostIntersectionsIndex); } } @@ -251,135 +234,124 @@ void FeatureMatcher::crisscrossFiltering(const vector queryKeypoints, } - // Returns true if successful, false otherwise bool FeatureMatcher::loadRecognitionSet(string country) { - std::ostringstream out; - out << config->getKeypointsRuntimeDir() << "/" << country << "/"; - string country_dir = out.str(); + std::ostringstream out; + out << config->getKeypointsRuntimeDir() << "/" << country << "/"; + string country_dir = out.str(); + if (DirectoryExists(country_dir.c_str())) + { + vector trainImages; + vector plateFiles = getFilesInDir(country_dir.c_str()); - if (DirectoryExists(country_dir.c_str())) + for (int i = 0; i < plateFiles.size(); i++) { - vector trainImages; - vector plateFiles = getFilesInDir(country_dir.c_str()); + if (hasEnding(plateFiles[i], ".jpg") == false) + continue; - for (int i = 0; i < plateFiles.size(); i++) + string fullpath = country_dir + plateFiles[i]; + Mat img = imread( fullpath ); + + // convert to gray and resize to the size of the templates + cvtColor(img, img, CV_BGR2GRAY); + resize(img, img, getSizeMaintainingAspect(img, config->stateIdImageWidthPx, config->stateIdimageHeightPx)); + + if( img.empty() ) { - if (hasEnding(plateFiles[i], ".jpg") == false) - continue; - - string fullpath = country_dir + plateFiles[i]; - Mat img = imread( fullpath ); - - // convert to gray and resize to the size of the templates - cvtColor(img, img, CV_BGR2GRAY); - resize(img, img, getSizeMaintainingAspect(img, config->stateIdImageWidthPx, config->stateIdimageHeightPx)); - - if( img.empty() ) - { - cout << "Can not read images" << endl; - return -1; - } - - - Mat descriptors; - - vector keypoints; - detector->detect( img, keypoints ); - extractor->compute(img, keypoints, descriptors); - - if (descriptors.cols > 0) - { - billMapping.push_back(plateFiles[i].substr(0, 2)); - trainImages.push_back(descriptors); - trainingImgKeypoints.push_back(keypoints); - } - + cout << "Can not read images" << endl; + return -1; } + Mat descriptors; - this->descriptorMatcher->add(trainImages); - this->descriptorMatcher->train(); + vector keypoints; + detector->detect( img, keypoints ); + extractor->compute(img, keypoints, descriptors); + + if (descriptors.cols > 0) + { + billMapping.push_back(plateFiles[i].substr(0, 2)); + trainImages.push_back(descriptors); + trainingImgKeypoints.push_back(keypoints); + } - return true; } - return false; + this->descriptorMatcher->add(trainImages); + this->descriptorMatcher->train(); + + return true; + } + + return false; } - - RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnImage, Mat* outputImage, - bool debug_on, vector debug_matches_array - ) + bool debug_on, vector debug_matches_array + ) { - RecognitionResult result; + RecognitionResult result; - result.haswinner = false; + result.haswinner = false; - Mat queryDescriptors; - vector queryKeypoints; + Mat queryDescriptors; + vector queryKeypoints; - detector->detect( queryImg, queryKeypoints ); - extractor->compute(queryImg, queryKeypoints, queryDescriptors); + detector->detect( queryImg, queryKeypoints ); + extractor->compute(queryImg, queryKeypoints, queryDescriptors); - - - if (queryKeypoints.size() <= 5) + if (queryKeypoints.size() <= 5) + { + // Cut it loose if there's less than 5 keypoints... nothing would ever match anyway and it could crash the matcher. + if (drawOnImage) { - // Cut it loose if there's less than 5 keypoints... nothing would ever match anyway and it could crash the matcher. - if (drawOnImage) - { - drawKeypoints( queryImg, queryKeypoints, *outputImage, CV_RGB(0, 255, 0), DrawMatchesFlags::DEFAULT ); - } - return result; + drawKeypoints( queryImg, queryKeypoints, *outputImage, CV_RGB(0, 255, 0), DrawMatchesFlags::DEFAULT ); } + return result; + } + vector filteredMatches; + surfStyleMatching( queryDescriptors, queryKeypoints, filteredMatches ); - vector filteredMatches; + // Create and initialize the counts to 0 + std::vector bill_match_counts( billMapping.size() ); - surfStyleMatching( queryDescriptors, queryKeypoints, filteredMatches ); + for (int i = 0; i < billMapping.size(); i++) + { + bill_match_counts[i] = 0; + } + for (int i = 0; i < filteredMatches.size(); i++) + { + bill_match_counts[filteredMatches[i].imgIdx]++; + //if (filteredMatches[i].imgIdx + } - // Create and initialize the counts to 0 - std::vector bill_match_counts( billMapping.size() ); - - for (int i = 0; i < billMapping.size(); i++) { bill_match_counts[i] = 0; } - - for (int i = 0; i < filteredMatches.size(); i++) + float max_count = 0; // represented as a percent (0 to 100) + int secondmost_count = 0; + int maxcount_index = -1; + for (int i = 0; i < billMapping.size(); i++) + { + if (bill_match_counts[i] > max_count && bill_match_counts[i] >= 4) { - bill_match_counts[filteredMatches[i].imgIdx]++; - //if (filteredMatches[i].imgIdx + secondmost_count = max_count; + if (secondmost_count <= 2) // A value of 1 or 2 is effectively 0 + secondmost_count = 0; + + max_count = bill_match_counts[i]; + maxcount_index = i; } + } - - - float max_count = 0; // represented as a percent (0 to 100) - int secondmost_count = 0; - int maxcount_index = -1; - for (int i = 0; i < billMapping.size(); i++) - { - if (bill_match_counts[i] > max_count && bill_match_counts[i] >= 4) - { - secondmost_count = max_count; - if (secondmost_count <= 2) // A value of 1 or 2 is effectively 0 - secondmost_count = 0; - - max_count = bill_match_counts[i]; - maxcount_index = i; - } - } - - float score = ((max_count - secondmost_count - 3) / 10) * 100; - if (score < 0) - score = 0; - else if (score > 100) - score = 100; - + float score = ((max_count - secondmost_count - 3) / 10) * 100; + if (score < 0) + score = 0; + else if (score > 100) + score = 100; if (score > 0) { @@ -389,28 +361,28 @@ RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnIma if (drawOnImage) { - vector positiveMatches; - for (int i = 0; i < filteredMatches.size(); i++) - { - if (filteredMatches[i].imgIdx == maxcount_index) - { - positiveMatches.push_back( queryKeypoints[filteredMatches[i].queryIdx] ); - } - } + vector positiveMatches; + for (int i = 0; i < filteredMatches.size(); i++) + { + if (filteredMatches[i].imgIdx == maxcount_index) + { + positiveMatches.push_back( queryKeypoints[filteredMatches[i].queryIdx] ); + } + } - Mat tmpImg; - drawKeypoints( queryImg, queryKeypoints, tmpImg, CV_RGB(185, 0, 0), DrawMatchesFlags::DEFAULT ); - drawKeypoints( tmpImg, positiveMatches, *outputImage, CV_RGB(0, 255, 0), DrawMatchesFlags::DEFAULT ); + Mat tmpImg; + drawKeypoints( queryImg, queryKeypoints, tmpImg, CV_RGB(185, 0, 0), DrawMatchesFlags::DEFAULT ); + drawKeypoints( tmpImg, positiveMatches, *outputImage, CV_RGB(0, 255, 0), DrawMatchesFlags::DEFAULT ); - if (result.haswinner == true) - { + if (result.haswinner == true) + { - std::ostringstream out; - out << result.winner << " (" << result.confidence << "%)"; + std::ostringstream out; + out << result.winner << " (" << result.confidence << "%)"; - // we detected a bill, let the people know! - //putText(*outputImage, out.str(), Point(15, 27), FONT_HERSHEY_DUPLEX, 1.1, CV_RGB(0, 0, 0), 2); - } + // we detected a bill, let the people know! + //putText(*outputImage, out.str(), Point(15, 27), FONT_HERSHEY_DUPLEX, 1.1, CV_RGB(0, 0, 0), 2); + } } } @@ -420,12 +392,11 @@ RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnIma for (int i = 0; i < billMapping.size(); i++) { - cout << billMapping[i] << " : " << bill_match_counts[i] << endl; + cout << billMapping[i] << " : " << bill_match_counts[i] << endl; } } return result; - } diff --git a/src/openalpr/featurematcher.h b/src/openalpr/featurematcher.h index a2ea8b3..a5d101f 100644 --- a/src/openalpr/featurematcher.h +++ b/src/openalpr/featurematcher.h @@ -38,7 +38,8 @@ using namespace std; -struct RecognitionResult { +struct RecognitionResult +{ bool haswinner; string winner; int confidence; @@ -54,7 +55,7 @@ class FeatureMatcher RecognitionResult recognize( const Mat& queryImg, bool drawOnImage, Mat* outputImage, - bool debug_on, vector debug_matches_array ); + bool debug_on, vector debug_matches_array ); bool loadRecognitionSet(string country); @@ -83,7 +84,7 @@ class FeatureMatcher void surfStyleMatching( const Mat& queryDescriptors, vector queryKeypoints, - vector& matches12 ); + vector& matches12 ); }; diff --git a/src/openalpr/licenseplatecandidate.cpp b/src/openalpr/licenseplatecandidate.cpp index 5c92af4..08831ea 100644 --- a/src/openalpr/licenseplatecandidate.cpp +++ b/src/openalpr/licenseplatecandidate.cpp @@ -19,13 +19,12 @@ #include "licenseplatecandidate.h" - LicensePlateCandidate::LicensePlateCandidate(Mat frame, Rect regionOfInterest, Config* config) { - this->config = config; + this->config = config; - this->frame = frame; - this->plateRegion = regionOfInterest; + this->frame = frame; + this->plateRegion = regionOfInterest; } LicensePlateCandidate::~LicensePlateCandidate() @@ -38,7 +37,6 @@ void LicensePlateCandidate::recognize() { charSegmenter = NULL; - this->confidence = 0; int expandX = round(this->plateRegion.width * 0.15); @@ -46,19 +44,14 @@ void LicensePlateCandidate::recognize() // expand box by 15% in all directions Rect expandedRegion = expandRect( this->plateRegion, expandX, expandY, frame.cols, frame.rows) ; - - - Mat plate_bgr = Mat(frame, expandedRegion); resize(plate_bgr, plate_bgr, Size(config->templateWidthPx, config->templateHeightPx)); Mat plate_bgr_cleaned = Mat(plate_bgr.size(), plate_bgr.type()); this->cleanupColors(plate_bgr, plate_bgr_cleaned); - CharacterRegion charRegion(plate_bgr, config); - if (charRegion.confidence > 10) { @@ -75,15 +68,12 @@ void LicensePlateCandidate::recognize() { this->plateCorners = transformPointsToOriginalImage(frame, plate_bgr, expandedRegion, smallPlateCorners); - this->deskewed = deSkewPlate(frame, this->plateCorners); - charSegmenter = new CharacterSegmenter(deskewed, charRegion.thresholdsInverted(), config); - //this->recognizedText = ocr->recognizedText; - //strcpy(this->recognizedText, ocr.recognizedText); + //strcpy(this->recognizedText, ocr.recognizedText); this->confidence = 100; @@ -91,13 +81,8 @@ void LicensePlateCandidate::recognize() charRegion.confidence = 0; } - } - - - - // Re-maps the coordinates from the smallImage to the coordinate space of the bigImage. vector LicensePlateCandidate::transformPointsToOriginalImage(Mat bigImage, Mat smallImage, Rect region, vector corners) { @@ -116,7 +101,6 @@ vector LicensePlateCandidate::transformPointsToOriginalImage(Mat bigIma return cornerPoints; } - Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector corners) { @@ -134,8 +118,8 @@ Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector corners) int height = round(((float) width) / aspect); if (height > config->ocrImageHeightPx) { - height = config->ocrImageHeightPx; - width = round(((float) height) * aspect); + height = config->ocrImageHeightPx; + width = round(((float) height) * aspect); } Mat deskewed(height, width, frame.type()); @@ -159,7 +143,6 @@ Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector corners) return deskewed; } - void LicensePlateCandidate::cleanupColors(Mat inputImage, Mat outputImage) { if (this->config->debugGeneral) @@ -174,26 +157,24 @@ void LicensePlateCandidate::cleanupColors(Mat inputImage, Mat outputImage) // Equalize intensity: if(intermediate.channels() >= 3) { - Mat ycrcb; + Mat ycrcb; - cvtColor(intermediate,ycrcb,CV_BGR2YCrCb); + cvtColor(intermediate,ycrcb,CV_BGR2YCrCb); - vector channels; - split(ycrcb,channels); + vector channels; + split(ycrcb,channels); - equalizeHist(channels[0], channels[0]); + equalizeHist(channels[0], channels[0]); - merge(channels,ycrcb); + merge(channels,ycrcb); - cvtColor(ycrcb,intermediate,CV_YCrCb2BGR); + cvtColor(ycrcb,intermediate,CV_YCrCb2BGR); - //ycrcb.release(); + //ycrcb.release(); } - bilateralFilter(intermediate, outputImage, 3, 25, 35); - if (this->config->debugGeneral) { displayImage(config, "After cleanup", outputImage); diff --git a/src/openalpr/ocr.cpp b/src/openalpr/ocr.cpp index ff7be2a..2be8c85 100644 --- a/src/openalpr/ocr.cpp +++ b/src/openalpr/ocr.cpp @@ -17,30 +17,26 @@ * along with this program. If not, see . */ - - - #include "ocr.h" OCR::OCR(Config* config) { this->config = config; - this->postProcessor = new PostProcess(config); + this->postProcessor = new PostProcess(config); - tesseract=new TessBaseAPI(); + tesseract=new TessBaseAPI(); - // Tesseract requires the prefix directory to be set as an env variable - vector tessdataPrefix(config->getTessdataPrefix().size() + 1); + // Tesseract requires the prefix directory to be set as an env variable + vector tessdataPrefix(config->getTessdataPrefix().size() + 1); - strcpy(tessdataPrefix.data(), config->getTessdataPrefix().c_str()); - putenv(tessdataPrefix.data()); + strcpy(tessdataPrefix.data(), config->getTessdataPrefix().c_str()); + putenv(tessdataPrefix.data()); - - tesseract->Init("", config->ocrLanguage.c_str() ); - tesseract->SetVariable("save_blob_choices", "T"); - //tesseract->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNPQRSTUVWXYZ1234567890"); - tesseract->SetPageSegMode(PSM_SINGLE_CHAR); + tesseract->Init("", config->ocrLanguage.c_str() ); + tesseract->SetVariable("save_blob_choices", "T"); + //tesseract->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNPQRSTUVWXYZ1234567890"); + tesseract->SetPageSegMode(PSM_SINGLE_CHAR); } OCR::~OCR() @@ -50,18 +46,14 @@ OCR::~OCR() delete tesseract; } - void OCR::performOCR(vector thresholds, vector charRegions) { - timespec startTime; getTime(&startTime); - postProcessor->clear(); - for (int i = 0; i < thresholds.size(); i++) { @@ -69,7 +61,6 @@ void OCR::performOCR(vector thresholds, vector charRegions) bitwise_not(thresholds[i], thresholds[i]); tesseract->SetImage((uchar*) thresholds[i].data, thresholds[i].size().width, thresholds[i].size().height, thresholds[i].channels(), thresholds[i].step1()); - for (int j = 0; j < charRegions.size(); j++) { Rect expandedRegion = expandRect( charRegions[j], 2, 2, thresholds[i].cols, thresholds[i].rows) ; @@ -79,52 +70,54 @@ void OCR::performOCR(vector thresholds, vector charRegions) tesseract::ResultIterator* ri = tesseract->GetIterator(); tesseract::PageIteratorLevel level = tesseract::RIL_SYMBOL; - do { - const char* symbol = ri->GetUTF8Text(level); - float conf = ri->Confidence(level); + do + { + const char* symbol = ri->GetUTF8Text(level); + float conf = ri->Confidence(level); - bool dontcare; - int fontindex = 0; - int pointsize = 0; - const char* fontName = ri->WordFontAttributes(&dontcare, &dontcare, &dontcare, &dontcare, &dontcare, &dontcare, &pointsize, &fontindex); + bool dontcare; + int fontindex = 0; + int pointsize = 0; + const char* fontName = ri->WordFontAttributes(&dontcare, &dontcare, &dontcare, &dontcare, &dontcare, &dontcare, &pointsize, &fontindex); - if(symbol != 0 && pointsize >= config->ocrMinFontSize) { - postProcessor->addLetter(*symbol, j, conf); - - - if (this->config->debugOcr) - printf("charpos%d: threshold %d: symbol %s, conf: %f font: %s (index %d) size %dpx", j, i, symbol, conf, fontName, fontindex, pointsize); - - bool indent = false; - tesseract::ChoiceIterator ci(*ri); - do { - const char* choice = ci.GetUTF8Text(); - - postProcessor->addLetter(*choice, j, ci.Confidence()); - - - //letterScores.addScore(*choice, j, ci.Confidence() - MIN_CONFIDENCE); - if (this->config->debugOcr) - { - if (indent) printf("\t\t "); - printf("\t- "); - printf("%s conf: %f\n", choice, ci.Confidence()); - } - - indent = true; - } while(ci.Next()); - } + if(symbol != 0 && pointsize >= config->ocrMinFontSize) + { + postProcessor->addLetter(*symbol, j, conf); if (this->config->debugOcr) - printf("---------------------------------------------\n"); + printf("charpos%d: threshold %d: symbol %s, conf: %f font: %s (index %d) size %dpx", j, i, symbol, conf, fontName, fontindex, pointsize); - delete[] symbol; - } while((ri->Next(level))); + bool indent = false; + tesseract::ChoiceIterator ci(*ri); + do + { + const char* choice = ci.GetUTF8Text(); + + postProcessor->addLetter(*choice, j, ci.Confidence()); + + //letterScores.addScore(*choice, j, ci.Confidence() - MIN_CONFIDENCE); + if (this->config->debugOcr) + { + if (indent) printf("\t\t "); + printf("\t- "); + printf("%s conf: %f\n", choice, ci.Confidence()); + } + + indent = true; + } + while(ci.Next()); + } + + if (this->config->debugOcr) + printf("---------------------------------------------\n"); + + delete[] symbol; + } + while((ri->Next(level))); delete ri; } - } if (config->debugTiming) @@ -134,7 +127,4 @@ void OCR::performOCR(vector thresholds, vector charRegions) cout << "OCR Time: " << diffclock(startTime, endTime) << "ms." << endl; } - - - } diff --git a/src/openalpr/ocr.h b/src/openalpr/ocr.h index 90a28da..119d7be 100644 --- a/src/openalpr/ocr.h +++ b/src/openalpr/ocr.h @@ -23,8 +23,8 @@ #ifndef OCR_H #define OCR_H - #include - #include +#include +#include #include "utility.h" #include "postprocess.h" diff --git a/src/openalpr/platecorners.cpp b/src/openalpr/platecorners.cpp index f8d2c43..68a91f9 100644 --- a/src/openalpr/platecorners.cpp +++ b/src/openalpr/platecorners.cpp @@ -17,7 +17,6 @@ * along with this program. If not, see . */ - #include "platecorners.h" PlateCorners::PlateCorners(Mat inputImage, PlateLines* plateLines, CharacterRegion* charRegion, Config* config) @@ -27,8 +26,6 @@ PlateCorners::PlateCorners(Mat inputImage, PlateLines* plateLines, CharacterRegi if (this->config->debugPlateCorners) cout << "PlateCorners constructor" << endl; - - this->inputImage = inputImage; this->plateLines = plateLines; this->charRegion = charRegion; @@ -36,7 +33,6 @@ PlateCorners::PlateCorners(Mat inputImage, PlateLines* plateLines, CharacterRegi this->bestHorizontalScore = 9999999999999; this->bestVerticalScore = 9999999999999; - Point topPoint = charRegion->getTopLine().midpoint(); Point bottomPoint = charRegion->getBottomLine().closestPointOnSegmentTo(topPoint); this->charHeight = distanceBetweenPoints(topPoint, bottomPoint); @@ -57,7 +53,7 @@ PlateCorners::~PlateCorners() vector PlateCorners::findPlateCorners() { if (this->config->debugPlateCorners) - cout << "PlateCorners::findPlateCorners" << endl; + cout << "PlateCorners::findPlateCorners" << endl; timespec startTime; getTime(&startTime); @@ -65,15 +61,14 @@ vector PlateCorners::findPlateCorners() int horizontalLines = this->plateLines->horizontalLines.size(); int verticalLines = this->plateLines->verticalLines.size(); - // layout horizontal lines for (int h1 = NO_LINE; h1 < horizontalLines; h1++) { for (int h2 = NO_LINE; h2 < horizontalLines; h2++) { - if (h1 == h2 && h1 != NO_LINE) continue; + if (h1 == h2 && h1 != NO_LINE) continue; - this->scoreHorizontals(h1, h2); + this->scoreHorizontals(h1, h2); } } @@ -81,35 +76,30 @@ vector PlateCorners::findPlateCorners() // layout vertical lines for (int v1 = NO_LINE; v1 < verticalLines; v1++) { - for (int v2 = NO_LINE; v2 < verticalLines; v2++) - { - if (v1 == v2 && v1 != NO_LINE) continue; + for (int v2 = NO_LINE; v2 < verticalLines; v2++) + { + if (v1 == v2 && v1 != NO_LINE) continue; - this->scoreVerticals(v1, v2); - } + this->scoreVerticals(v1, v2); + } } - if (this->config->debugPlateCorners) { - cout << "Drawing debug stuff..." << endl; + cout << "Drawing debug stuff..." << endl; - Mat imgCorners = Mat(inputImage.size(), inputImage.type()); - inputImage.copyTo(imgCorners); - for (int i = 0; i < 4; i++) - circle(imgCorners, charRegion->getCharArea()[i], 2, Scalar(0, 0, 0)); + Mat imgCorners = Mat(inputImage.size(), inputImage.type()); + inputImage.copyTo(imgCorners); + for (int i = 0; i < 4; i++) + circle(imgCorners, charRegion->getCharArea()[i], 2, Scalar(0, 0, 0)); + line(imgCorners, this->bestTop.p1, this->bestTop.p2, Scalar(255, 0, 0), 1, CV_AA); + line(imgCorners, this->bestRight.p1, this->bestRight.p2, Scalar(0, 0, 255), 1, CV_AA); + line(imgCorners, this->bestBottom.p1, this->bestBottom.p2, Scalar(0, 0, 255), 1, CV_AA); + line(imgCorners, this->bestLeft.p1, this->bestLeft.p2, Scalar(255, 0, 0), 1, CV_AA); - line(imgCorners, this->bestTop.p1, this->bestTop.p2, Scalar(255, 0, 0), 1, CV_AA); - line(imgCorners, this->bestRight.p1, this->bestRight.p2, Scalar(0, 0, 255), 1, CV_AA); - line(imgCorners, this->bestBottom.p1, this->bestBottom.p2, Scalar(0, 0, 255), 1, CV_AA); - line(imgCorners, this->bestLeft.p1, this->bestLeft.p2, Scalar(255, 0, 0), 1, CV_AA); - - - - - displayImage(config, "Winning top/bottom Boundaries", imgCorners); + displayImage(config, "Winning top/bottom Boundaries", imgCorners); } @@ -127,8 +117,6 @@ vector PlateCorners::findPlateCorners() corners.push_back(bestBottom.intersection(bestRight)); corners.push_back(bestBottom.intersection(bestLeft)); - - if (config->debugTiming) { timespec endTime; @@ -139,7 +127,6 @@ vector PlateCorners::findPlateCorners() return corners; } - void PlateCorners::scoreVerticals(int v1, int v2) { @@ -148,8 +135,6 @@ void PlateCorners::scoreVerticals(int v1, int v2) LineSegment left; LineSegment right; - - float charHeightToPlateWidthRatio = config->plateWidthMM / config->charHeightMM; float idealPixelWidth = this->charHeight * (charHeightToPlateWidthRatio * 1.05); // Add 10% so we don't clip any characters @@ -183,8 +168,6 @@ void PlateCorners::scoreVerticals(int v1, int v2) score += SCORING_MISSING_SEGMENT_PENALTY_VERTICAL; } - - // Make sure this line is to the left of our license plate letters if (left.isPointBelowLine(charRegion->getCharBoxLeft().midpoint()) == false) return; @@ -193,7 +176,6 @@ void PlateCorners::scoreVerticals(int v1, int v2) if (right.isPointBelowLine(charRegion->getCharBoxRight().midpoint())) return; - ///////////////////////////////////////////////////////////////////////// // Score "Distance from the edge... ///////////////////////////////////////////////////////////////////////// @@ -204,7 +186,6 @@ void PlateCorners::scoreVerticals(int v1, int v2) float distanceFromEdge = leftDistanceFromEdge + rightDistanceFromEdge; score += distanceFromEdge * SCORING_VERTICALDISTANCE_FROMEDGE_WEIGHT; - ///////////////////////////////////////////////////////////////////////// // Score "Boxiness" of the 4 lines. How close is it to a parallelogram? ///////////////////////////////////////////////////////////////////////// @@ -213,12 +194,10 @@ void PlateCorners::scoreVerticals(int v1, int v2) score += (verticalAngleDiff) * SCORING_BOXINESS_WEIGHT; - ////////////////////////////////////////////////////////////////////////// // SCORE the shape wrt character position and height relative to position ////////////////////////////////////////////////////////////////////////// - Point leftMidLinePoint = left.closestPointOnSegmentTo(charRegion->getCharBoxLeft().midpoint()); Point rightMidLinePoint = right.closestPointOnSegmentTo(charRegion->getCharBoxRight().midpoint()); @@ -230,7 +209,6 @@ void PlateCorners::scoreVerticals(int v1, int v2) { float scorecomponent; - if (this->config->debugPlateCorners) { cout << "xx xx Score: charHeight " << this->charHeight << endl; @@ -277,7 +255,6 @@ void PlateCorners::scoreHorizontals(int h1, int h2) float charHeightToPlateHeightRatio = config->plateHeightMM / config->charHeightMM; float idealPixelHeight = this->charHeight * charHeightToPlateHeightRatio; - if (h1 == NO_LINE && h2 == NO_LINE) { // return; @@ -308,39 +285,26 @@ void PlateCorners::scoreHorizontals(int h1, int h2) score += SCORING_MISSING_SEGMENT_PENALTY_HORIZONTAL; } - - // Make sure this line is above our license plate letters if (top.isPointBelowLine(charRegion->getCharBoxTop().midpoint()) == false) return; - // Make sure this line is below our license plate letters if (bottom.isPointBelowLine(charRegion->getCharBoxBottom().midpoint())) return; - - - - - // We now have 4 possible lines. Let's put them to the test and score them... - - - ///////////////////////////////////////////////////////////////////////// // Score "Boxiness" of the 4 lines. How close is it to a parallelogram? ///////////////////////////////////////////////////////////////////////// float horizontalAngleDiff = abs(top.angle - bottom.angle); - score += (horizontalAngleDiff) * SCORING_BOXINESS_WEIGHT; // if (this->debug) // cout << "PlateCorners boxiness score: " << (horizontalAngleDiff + verticalAngleDiff) * SCORING_BOXINESS_WEIGHT << endl; - ////////////////////////////////////////////////////////////////////////// // SCORE the shape wrt character position and height relative to position ////////////////////////////////////////////////////////////////////////// @@ -351,7 +315,6 @@ void PlateCorners::scoreHorizontals(int h1, int h2) // Get the height difference - float heightRatio = charHeight / plateHeightPx; float idealHeightRatio = (config->charHeightMM / config->plateHeightMM); //if (leftRatio < MIN_CHAR_HEIGHT_RATIO || leftRatio > MAX_CHAR_HEIGHT_RATIO || rightRatio < MIN_CHAR_HEIGHT_RATIO || rightRatio > MAX_CHAR_HEIGHT_RATIO) @@ -367,7 +330,6 @@ void PlateCorners::scoreHorizontals(int h1, int h2) // float idealBottomDistance = charHeight * (BOTTOM_WHITESPACE_HEIGHT_MM / CHARACTER_HEIGHT_MM); // float distScore = abs(topDistance - idealTopDistance) + abs(bottomDistance - idealBottomDistance); - score += heightRatioDiff * SCORING_PLATEHEIGHT_WEIGHT; ////////////////////////////////////////////////////////////////////////// @@ -398,14 +360,11 @@ void PlateCorners::scoreHorizontals(int h1, int h2) float charanglediff = abs(charAngle - top.angle) + abs(charAngle - bottom.angle); - score += charanglediff * SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT; // if (this->debug) // cout << "PlateCorners boxiness score: " << charanglediff * SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT << endl; - - if (score < this->bestHorizontalScore) { float scorecomponent; @@ -442,6 +401,4 @@ void PlateCorners::scoreHorizontals(int h1, int h2) bestBottom = LineSegment(bottom.p1.x, bottom.p1.y, bottom.p2.x, bottom.p2.y); } - - } diff --git a/src/openalpr/platelines.cpp b/src/openalpr/platelines.cpp index f19e05b..9235d61 100644 --- a/src/openalpr/platelines.cpp +++ b/src/openalpr/platelines.cpp @@ -19,7 +19,6 @@ #include "platelines.h" - PlateLines::PlateLines(Config* config) { this->config = config; @@ -28,7 +27,6 @@ PlateLines::PlateLines(Config* config) if (debug) cout << "PlateLines constructor" << endl; - } PlateLines::~PlateLines() @@ -36,22 +34,18 @@ PlateLines::~PlateLines() } - - void PlateLines::processImage(Mat inputImage, float sensitivity) { if (this->debug) cout << "PlateLines findLines" << endl; - timespec startTime; getTime(&startTime); - Mat smoothed(inputImage.size(), inputImage.type()); inputImage.copyTo(smoothed); - int morph_elem = 2; - int morph_size = 2; + int morph_elem = 2; + int morph_size = 2; Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) ); morphologyEx( smoothed, smoothed, MORPH_CLOSE, element ); @@ -65,12 +59,9 @@ void PlateLines::processImage(Mat inputImage, float sensitivity) element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) ); morphologyEx( smoothed, smoothed, MORPH_OPEN, element ); - - Mat edges(inputImage.size(), inputImage.type()); Canny(smoothed, edges, 66, 133); - vector hlines = this->getLines(edges, sensitivity, false); vector vlines = this->getLines(edges, sensitivity, true); for (int i = 0; i < hlines.size(); i++) @@ -78,9 +69,6 @@ void PlateLines::processImage(Mat inputImage, float sensitivity) for (int i = 0; i < vlines.size(); i++) this->verticalLines.push_back(vlines[i]); - - - // if debug is enabled, draw the image if (this->debug) { @@ -109,8 +97,6 @@ void PlateLines::processImage(Mat inputImage, float sensitivity) displayImage(config, "Hough Lines", dashboard); } - - if (config->debugTiming) { timespec endTime; @@ -119,7 +105,6 @@ void PlateLines::processImage(Mat inputImage, float sensitivity) } //smoothed.release(); - //////////////// METHOD2!!!!!!!//////////////////// /* @@ -127,33 +112,28 @@ void PlateLines::processImage(Mat inputImage, float sensitivity) Mat imgCanny; GaussianBlur(inputImage, imgBlur, Size(9, 9), 1, 1); - - Canny(imgBlur, imgCanny, 10, 30, 3); - - //int morph_elem = 2; //int morph_size = 1; //Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) ); morphologyEx( imgCanny, imgCanny, MORPH_CLOSE, element ); - Mat imgShaped; imgCanny.copyTo(imgShaped); //Find contours of possibles characters vector< vector< Point> > biggestShapes; findContours(imgShaped, - biggestShapes, // a vector of contours - CV_RETR_EXTERNAL, // retrieve the external contours - CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours + biggestShapes, // a vector of contours + CV_RETR_EXTERNAL, // retrieve the external contours + CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours // Draw blue contours on a white image //cvtColor(imgShaped, imgShaped, CV_GRAY2RGB); cv::drawContours(imgShaped,biggestShapes, - -1, // draw all contours - cv::Scalar(255,255,255), // in blue - 1); // with a thickness of 1 + -1, // draw all contours + cv::Scalar(255,255,255), // in blue + 1); // with a thickness of 1 displayImage(config, "Blurred", imgCanny); displayImage(config, "Blurred Contours", imgShaped); @@ -187,7 +167,6 @@ vector PlateLines::getLines(Mat edges, bool vertical) vector errors; lswms.run(edges, lsegs, errors); - for( size_t i = 0; i < lsegs.size(); i++ ) { @@ -247,7 +226,6 @@ vector PlateLines::getLines(Mat edges, bool vertical) } */ - vector PlateLines::getLines(Mat edges, float sensitivityMultiplier, bool vertical) { if (this->debug) @@ -267,100 +245,92 @@ vector PlateLines::getLines(Mat edges, float sensitivityMultiplier, HoughLines( edges, allLines, 1, CV_PI/180, sensitivity, 0, 0 ); - for( size_t i = 0; i < allLines.size(); i++ ) { - float rho = allLines[i][0], theta = allLines[i][1]; - Point pt1, pt2; - double a = cos(theta), b = sin(theta); - double x0 = a*rho, y0 = b*rho; + float rho = allLines[i][0], theta = allLines[i][1]; + Point pt1, pt2; + double a = cos(theta), b = sin(theta); + double x0 = a*rho, y0 = b*rho; - double angle = theta * (180 / CV_PI); - pt1.x = cvRound(x0 + 1000*(-b)); - pt1.y = cvRound(y0 + 1000*(a)); - pt2.x = cvRound(x0 - 1000*(-b)); - pt2.y = cvRound(y0 - 1000*(a)); + double angle = theta * (180 / CV_PI); + pt1.x = cvRound(x0 + 1000*(-b)); + pt1.y = cvRound(y0 + 1000*(a)); + pt2.x = cvRound(x0 - 1000*(-b)); + pt2.y = cvRound(y0 - 1000*(a)); - if (vertical) - { - if (angle < 20 || angle > 340 || (angle > 160 && angle < 210)) - { - // good vertical + if (vertical) + { + if (angle < 20 || angle > 340 || (angle > 160 && angle < 210)) + { + // good vertical - LineSegment line; - if (pt1.y <= pt2.y) - line = LineSegment(pt2.x, pt2.y, pt1.x, pt1.y); - else - line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y); + LineSegment line; + if (pt1.y <= pt2.y) + line = LineSegment(pt2.x, pt2.y, pt1.x, pt1.y); + else + line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y); - // Get rid of the -1000, 1000 stuff. Terminate at the edges of the image - // Helps with debugging/rounding issues later - LineSegment top(0, 0, edges.cols, 0); - LineSegment bottom(0, edges.rows, edges.cols, edges.rows); - Point p1 = line.intersection(bottom); - Point p2 = line.intersection(top); - filteredLines.push_back(LineSegment(p1.x, p1.y, p2.x, p2.y)); - } - } - else - { + // Get rid of the -1000, 1000 stuff. Terminate at the edges of the image + // Helps with debugging/rounding issues later + LineSegment top(0, 0, edges.cols, 0); + LineSegment bottom(0, edges.rows, edges.cols, edges.rows); + Point p1 = line.intersection(bottom); + Point p2 = line.intersection(top); + filteredLines.push_back(LineSegment(p1.x, p1.y, p2.x, p2.y)); + } + } + else + { - if ( (angle > 70 && angle < 110) || (angle > 250 && angle < 290)) - { - // good horizontal + if ( (angle > 70 && angle < 110) || (angle > 250 && angle < 290)) + { + // good horizontal - LineSegment line; - if (pt1.x <= pt2.x) - line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y); - else - line =LineSegment(pt2.x, pt2.y, pt1.x, pt1.y); + LineSegment line; + if (pt1.x <= pt2.x) + line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y); + else + line =LineSegment(pt2.x, pt2.y, pt1.x, pt1.y); - // Get rid of the -1000, 1000 stuff. Terminate at the edges of the image - // Helps with debugging/ rounding issues later - int newY1 = line.getPointAt(0); - int newY2 = line.getPointAt(edges.cols); + // Get rid of the -1000, 1000 stuff. Terminate at the edges of the image + // Helps with debugging/ rounding issues later + int newY1 = line.getPointAt(0); + int newY2 = line.getPointAt(edges.cols); - filteredLines.push_back(LineSegment(0, newY1, edges.cols, newY2)); - } - } + filteredLines.push_back(LineSegment(0, newY1, edges.cols, newY2)); + } + } } - return filteredLines; } - - - - Mat PlateLines::customGrayscaleConversion(Mat src) { Mat img_hsv; cvtColor(src,img_hsv,CV_BGR2HSV); + Mat grayscale = Mat(img_hsv.size(), CV_8U ); + Mat hue(img_hsv.size(), CV_8U ); - Mat grayscale = Mat(img_hsv.size(), CV_8U ); - Mat hue(img_hsv.size(), CV_8U ); - - for (int row = 0; row < img_hsv.rows; row++) + for (int row = 0; row < img_hsv.rows; row++) + { + for (int col = 0; col < img_hsv.cols; col++) { - for (int col = 0; col < img_hsv.cols; col++) - { - int h = (int) img_hsv.at(row, col)[0]; - int s = (int) img_hsv.at(row, col)[1]; - int v = (int) img_hsv.at(row, col)[2]; + int h = (int) img_hsv.at(row, col)[0]; + int s = (int) img_hsv.at(row, col)[1]; + int v = (int) img_hsv.at(row, col)[2]; - int pixval = pow(v, 1.05); + int pixval = pow(v, 1.05); + if (pixval > 255) + pixval = 255; + grayscale.at(row, col) = pixval; - if (pixval > 255) - pixval = 255; - grayscale.at(row, col) = pixval; - - hue.at(row, col) = h * (255.0 / 180.0); - } + hue.at(row, col) = h * (255.0 / 180.0); } + } - //displayImage(config, "Hue", hue); - return grayscale; + //displayImage(config, "Hue", hue); + return grayscale; } diff --git a/src/openalpr/postprocess.cpp b/src/openalpr/postprocess.cpp index 6501810..bc18921 100644 --- a/src/openalpr/postprocess.cpp +++ b/src/openalpr/postprocess.cpp @@ -19,7 +19,6 @@ #include "postprocess.h" - PostProcess::PostProcess(Config* config) { this->config = config; @@ -29,12 +28,11 @@ PostProcess::PostProcess(Config* config) std::ifstream infile(filename.str().c_str()); - string region, pattern; while (infile >> region >> pattern) { RegexRule* rule = new RegexRule(region, pattern); - //cout << "REGION: " << region << " PATTERN: " << pattern << endl; + //cout << "REGION: " << region << " PATTERN: " << pattern << endl; if (rules.find(region) == rules.end()) { @@ -61,16 +59,16 @@ PostProcess::~PostProcess() // TODO: Delete all entries in rules vector map >::iterator iter; - for (iter = rules.begin(); iter != rules.end(); ++iter) { + for (iter = rules.begin(); iter != rules.end(); ++iter) + { for (int i = 0; i < iter->second.size(); i++) { - delete iter->second[i]; + delete iter->second[i]; } } } - void PostProcess::addLetter(char letter, int charposition, float score) { if (score < config->postProcessMinConfidence) @@ -80,8 +78,8 @@ void PostProcess::addLetter(char letter, int charposition, float score) if (score < config->postProcessConfidenceSkipLevel) { - float adjustedScore = abs(config->postProcessConfidenceSkipLevel - score) + config->postProcessMinConfidence; - insertLetter(SKIP_CHAR, charposition, adjustedScore ); + float adjustedScore = abs(config->postProcessConfidenceSkipLevel - score) + config->postProcessMinConfidence; + insertLetter(SKIP_CHAR, charposition, adjustedScore ); } //if (letter == '0') @@ -96,25 +94,24 @@ void PostProcess::insertLetter(char letter, int charposition, float score) score = score - config->postProcessMinConfidence; - int existingIndex = -1; if (letters.size() < charposition + 1) { - for (int i = letters.size(); i < charposition + 1; i++) - { - vector tmp; - letters.push_back(tmp); - } + for (int i = letters.size(); i < charposition + 1; i++) + { + vector tmp; + letters.push_back(tmp); + } } for (int i = 0; i < letters[charposition].size(); i++) { - if (letters[charposition][i].letter == letter && - letters[charposition][i].charposition == charposition) - { - existingIndex = i; - break; - } + if (letters[charposition][i].letter == letter && + letters[charposition][i].charposition == charposition) + { + existingIndex = i; + break; + } } if (existingIndex == -1) @@ -128,18 +125,17 @@ void PostProcess::insertLetter(char letter, int charposition, float score) } else { - letters[charposition][existingIndex].occurences = letters[charposition][existingIndex].occurences + 1; - letters[charposition][existingIndex].totalscore = letters[charposition][existingIndex].totalscore + score; + letters[charposition][existingIndex].occurences = letters[charposition][existingIndex].occurences + 1; + letters[charposition][existingIndex].totalscore = letters[charposition][existingIndex].totalscore + score; } } - void PostProcess::clear() { for (int i = 0; i < letters.size(); i++) { - letters[i].clear(); + letters[i].clear(); } letters.resize(0); @@ -157,22 +153,18 @@ void PostProcess::analyze(string templateregion, int topn) timespec startTime; getTime(&startTime); - - // Get a list of missing positions for (int i = letters.size() -1; i >= 0; i--) { if (letters[i].size() == 0) { - unknownCharPositions.push_back(i); + unknownCharPositions.push_back(i); } } - if (letters.size() == 0) return; - // Sort the letters as they are for (int i = 0; i < letters.size(); i++) { @@ -180,8 +172,6 @@ void PostProcess::analyze(string templateregion, int topn) sort(letters[i].begin(), letters[i].end(), letterCompare); } - - if (this->config->debugPostProcess) { @@ -189,7 +179,7 @@ void PostProcess::analyze(string templateregion, int topn) for (int i = 0; i < letters.size(); i++) { for (int j = 0; j < letters[i].size(); j++) - cout << "PostProcess Letter: " << letters[i][j].charposition << " " << letters[i][j].letter << " -- score: " << letters[i][j].totalscore << " -- occurences: " << letters[i][j].occurences << endl; + cout << "PostProcess Letter: " << letters[i][j].charposition << " " << letters[i][j].letter << " -- score: " << letters[i][j].totalscore << " -- occurences: " << letters[i][j].occurences << endl; } } @@ -211,7 +201,6 @@ void PostProcess::analyze(string templateregion, int topn) vector tmp; findAllPermutations(tmp, 0, config->postProcessMaxSubstitutions); - timespec sortStartTime; getTime(&sortStartTime); @@ -228,11 +217,8 @@ void PostProcess::analyze(string templateregion, int topn) cout << " -- PostProcess Sort Time: " << diffclock(sortStartTime, sortEndTime) << "ms." << endl; } - - matchesTemplate = false; - if (templateregion != "") { vector regionRules = rules[templateregion]; @@ -241,22 +227,20 @@ void PostProcess::analyze(string templateregion, int topn) { for (int j = 0; j < regionRules.size(); j++) { - allPossibilities[i].matchesTemplate = regionRules[j]->match(allPossibilities[i].letters); - if (allPossibilities[i].matchesTemplate) - { - allPossibilities[i].letters = regionRules[j]->filterSkips(allPossibilities[i].letters); - //bestChars = regionRules[j]->filterSkips(allPossibilities[i].letters); - matchesTemplate = true; - break; - } + allPossibilities[i].matchesTemplate = regionRules[j]->match(allPossibilities[i].letters); + if (allPossibilities[i].matchesTemplate) + { + allPossibilities[i].letters = regionRules[j]->filterSkips(allPossibilities[i].letters); + //bestChars = regionRules[j]->filterSkips(allPossibilities[i].letters); + matchesTemplate = true; + break; + } } - - if (i >= topn - 1) - break; + break; //if (matchesTemplate || i >= TOP_N - 1) - //break; + //break; } } @@ -264,11 +248,11 @@ void PostProcess::analyze(string templateregion, int topn) { for (int z = 0; z < allPossibilities.size(); z++) { - if (allPossibilities[z].matchesTemplate) - { - bestChars = allPossibilities[z].letters; - break; - } + if (allPossibilities[z].matchesTemplate) + { + bestChars = allPossibilities[z].letters; + break; + } } } else @@ -276,7 +260,7 @@ void PostProcess::analyze(string templateregion, int topn) bestChars = allPossibilities[0].letters; } - // Now adjust the confidence scores to a percentage value + // Now adjust the confidence scores to a percentage value if (allPossibilities.size() > 0) { float maxPercentScore = calculateMaxConfidenceScore(); @@ -289,28 +273,23 @@ void PostProcess::analyze(string templateregion, int topn) } - - if (this->config->debugPostProcess) { - // Print top words for (int i = 0; i < allPossibilities.size(); i++) { cout << "Top " << topn << " Possibilities: " << allPossibilities[i].letters << " :\t" << allPossibilities[i].totalscore; if (allPossibilities[i].letters == bestChars) - cout << " <--- "; + cout << " <--- "; cout << endl; if (i >= topn - 1) - break; + break; } cout << allPossibilities.size() << " total permutations" << endl; } - - if (config->debugTiming) { timespec endTime; @@ -333,8 +312,8 @@ float PostProcess::calculateMaxConfidenceScore() { if (letters[i].size() > 0) { - totalScore += (letters[i][0].totalscore / letters[i][0].occurences) + config->postProcessMinConfidence; - numScores++; + totalScore += (letters[i][0].totalscore / letters[i][0].occurences) + config->postProcessMinConfidence; + numScores++; } } @@ -372,19 +351,18 @@ vector PostProcess::getMaxDepth(int topn) nextLeastDropCharPos = getNextLeastDrop(depth); } - return depth; } int PostProcess::getPermutationCount(vector depth) { int permutationCount = 1; - for (int i = 0; i < depth.size(); i++) - { - permutationCount *= (depth[i] + 1); - } + for (int i = 0; i < depth.size(); i++) + { + permutationCount *= (depth[i] + 1); + } - return permutationCount; + return permutationCount; } int PostProcess::getNextLeastDrop(vector depth) @@ -392,21 +370,21 @@ int PostProcess::getNextLeastDrop(vector depth) int nextLeastDropCharPos = -1; float leastNextDrop = 99999999999; - for (int i = 0; i < letters.size(); i++) + for (int i = 0; i < letters.size(); i++) + { + if (depth[i] + 1 >= letters[i].size()) + continue; + + float drop = letters[i][depth[i]].totalscore - letters[i][depth[i]+1].totalscore; + + if (drop < leastNextDrop) { - if (depth[i] + 1 >= letters[i].size()) - continue; - - float drop = letters[i][depth[i]].totalscore - letters[i][depth[i]+1].totalscore; - - if (drop < leastNextDrop) - { - nextLeastDropCharPos = i; - leastNextDrop = drop; - } + nextLeastDropCharPos = i; + leastNextDrop = drop; } + } - return nextLeastDropCharPos; + return nextLeastDropCharPos; } const vector PostProcess::getResults() @@ -426,23 +404,23 @@ void PostProcess::findAllPermutations(vector prevletters, int charPos, i if (charPos == letters.size() - 1) { - // Last letter, add the word - PPResult possibility; - possibility.letters = ""; - possibility.totalscore = 0; - possibility.matchesTemplate = false; - for (int z = 0; z < prevletters.size(); z++) - { - if (prevletters[z].letter != SKIP_CHAR) - possibility.letters = possibility.letters + prevletters[z].letter; - possibility.totalscore = possibility.totalscore + prevletters[z].totalscore; - } + // Last letter, add the word + PPResult possibility; + possibility.letters = ""; + possibility.totalscore = 0; + possibility.matchesTemplate = false; + for (int z = 0; z < prevletters.size(); z++) + { + if (prevletters[z].letter != SKIP_CHAR) + possibility.letters = possibility.letters + prevletters[z].letter; + possibility.totalscore = possibility.totalscore + prevletters[z].totalscore; + } - if (letters[charPos][i].letter != SKIP_CHAR) - possibility.letters = possibility.letters + letters[charPos][i].letter; - possibility.totalscore = possibility.totalscore +letters[charPos][i].totalscore; + if (letters[charPos][i].letter != SKIP_CHAR) + possibility.letters = possibility.letters + letters[charPos][i].letter; + possibility.totalscore = possibility.totalscore +letters[charPos][i].totalscore; - allPossibilities.push_back(possibility); + allPossibilities.push_back(possibility); } else { @@ -450,9 +428,9 @@ void PostProcess::findAllPermutations(vector prevletters, int charPos, i float scorePercentDiff = abs( letters[charPos][0].totalscore - letters[charPos][i].totalscore ) / letters[charPos][0].totalscore; if (i != 0 && letters[charPos][i].letter != SKIP_CHAR && scorePercentDiff > 0.10f ) - findAllPermutations(prevletters, charPos + 1, substitutionsLeft - 1); + findAllPermutations(prevletters, charPos + 1, substitutionsLeft - 1); else - findAllPermutations(prevletters, charPos + 1, substitutionsLeft); + findAllPermutations(prevletters, charPos + 1, substitutionsLeft); prevletters.pop_back(); } @@ -460,19 +438,15 @@ void PostProcess::findAllPermutations(vector prevletters, int charPos, i if (letters[charPos].size() == 0) { - // No letters for this char position... - // Just pass it along - findAllPermutations(prevletters, charPos + 1, substitutionsLeft); + // No letters for this char position... + // Just pass it along + findAllPermutations(prevletters, charPos + 1, substitutionsLeft); } - - } - - - -bool wordCompare( const PPResult &left, const PPResult &right ){ +bool wordCompare( const PPResult &left, const PPResult &right ) +{ if (left.totalscore < right.totalscore) return false; return true; @@ -486,7 +460,6 @@ bool letterCompare( const Letter &left, const Letter &right ) return true; } - RegexRule::RegexRule(string region, string pattern) { this->original = pattern; @@ -495,31 +468,31 @@ RegexRule::RegexRule(string region, string pattern) numchars = 0; for (int i = 0; i < pattern.size(); i++) { - if (pattern.at(i) == '[') + if (pattern.at(i) == '[') + { + while (pattern.at(i) != ']' ) { - while (pattern.at(i) != ']' ) - { - this->regex = this->regex + pattern.at(i); - i++; - } - this->regex = this->regex + ']'; + this->regex = this->regex + pattern.at(i); + i++; + } + this->regex = this->regex + ']'; - } - else if (pattern.at(i) == '?') - { - this->regex = this->regex + '.'; - this->skipPositions.push_back(numchars); - } - else if (pattern.at(i) == '@') - { - this->regex = this->regex + "\\a"; - } - else if (pattern.at(i) == '#') - { - this->regex = this->regex + "\\d"; - } + } + else if (pattern.at(i) == '?') + { + this->regex = this->regex + '.'; + this->skipPositions.push_back(numchars); + } + else if (pattern.at(i) == '@') + { + this->regex = this->regex + "\\a"; + } + else if (pattern.at(i) == '#') + { + this->regex = this->regex + "\\d"; + } - numchars++; + numchars++; } trexp.Compile(this->regex.c_str()); @@ -529,7 +502,6 @@ RegexRule::RegexRule(string region, string pattern) // cout << "AA Skip position: " << skipPositions[z] << endl; } - bool RegexRule::match(string text) { if (text.length() != numchars) @@ -544,17 +516,17 @@ string RegexRule::filterSkips(string text) for (int i = 0; i < text.size(); i++) { bool skip = false; - for (int j = 0; j < skipPositions.size(); j++) + for (int j = 0; j < skipPositions.size(); j++) + { + if (skipPositions[j] == i) { - if (skipPositions[j] == i) - { - skip = true; - break; - } + skip = true; + break; } + } - if (skip == false) - response = response + text[i]; + if (skip == false) + response = response + text[i]; } return response; diff --git a/src/openalpr/postprocess.h b/src/openalpr/postprocess.h index 78a3377..446f5f1 100644 --- a/src/openalpr/postprocess.h +++ b/src/openalpr/postprocess.h @@ -21,13 +21,13 @@ #ifndef POSTPROCESS_H #define POSTPROCESS_H - #include "TRexpp.h" - #include "constants.h" - #include "utility.h" - #include - #include - #include - #include +#include "TRexpp.h" +#include "constants.h" +#include "utility.h" +#include +#include +#include +#include #include "config.h" using namespace std; @@ -37,17 +37,17 @@ using namespace std; struct Letter { - char letter; - int charposition; - float totalscore; - int occurences; + char letter; + int charposition; + float totalscore; + int occurences; }; struct PPResult { - string letters; - float totalscore; - bool matchesTemplate; + string letters; + float totalscore; + bool matchesTemplate; }; diff --git a/src/openalpr/regiondetector.cpp b/src/openalpr/regiondetector.cpp index 3394d8e..3f8f061 100644 --- a/src/openalpr/regiondetector.cpp +++ b/src/openalpr/regiondetector.cpp @@ -17,39 +17,33 @@ * along with this program. If not, see . */ - - #include "regiondetector.h" - RegionDetector::RegionDetector(Config* config) { this->config = config; // Don't scale. Can change this in the future (i.e., maximum resolution preference, or some such). - this->scale_factor = 1.0f; - - // Load either the regular or OpenCL version of the cascade classifier - if (config->opencl_enabled) - { - this->plate_cascade = new ocl::OclCascadeClassifier(); - } - else - { - this->plate_cascade = new CascadeClassifier(); - } - - - if( this->plate_cascade->load( config->getCascadeRuntimeDir() + config->country + ".xml" ) ) - { - this->loaded = true; - } - else - { - this->loaded = false; - printf("--(!)Error loading classifier\n"); - } + this->scale_factor = 1.0f; + // Load either the regular or OpenCL version of the cascade classifier + if (config->opencl_enabled) + { + this->plate_cascade = new ocl::OclCascadeClassifier(); + } + else + { + this->plate_cascade = new CascadeClassifier(); + } + if( this->plate_cascade->load( config->getCascadeRuntimeDir() + config->country + ".xml" ) ) + { + this->loaded = true; + } + else + { + this->loaded = false; + printf("--(!)Error loading classifier\n"); + } } @@ -58,14 +52,11 @@ RegionDetector::~RegionDetector() delete this->plate_cascade; } - - bool RegionDetector::isLoaded() { return this->loaded; } - vector RegionDetector::detect(Mat frame) { @@ -77,7 +68,6 @@ vector RegionDetector::detect(Mat frame) return regionsOfInterest; } - /** @function detectAndDisplay */ vector RegionDetector::doCascade(Mat frame) { @@ -91,44 +81,41 @@ vector RegionDetector::doCascade(Mat frame) resize(frame, frame, Size(w * this->scale_factor, h * this->scale_factor)); //-- Detect plates - timespec startTime; - getTime(&startTime); + timespec startTime; + getTime(&startTime); - Size minSize(config->minPlateSizeWidthPx * this->scale_factor, config->minPlateSizeHeightPx * this->scale_factor); - Size maxSize(w * config->maxPlateWidthPercent * this->scale_factor, h * config->maxPlateHeightPercent * this->scale_factor); + Size minSize(config->minPlateSizeWidthPx * this->scale_factor, config->minPlateSizeHeightPx * this->scale_factor); + Size maxSize(w * config->maxPlateWidthPercent * this->scale_factor, h * config->maxPlateHeightPercent * this->scale_factor); - if (config->opencl_enabled) - { - ocl::oclMat openclFrame(frame); - ((ocl::OclCascadeClassifier*) plate_cascade)->detectMultiScale(openclFrame, plates, 1.1, 3, 0, minSize, maxSize); - } - else - { + if (config->opencl_enabled) + { + ocl::oclMat openclFrame(frame); + ((ocl::OclCascadeClassifier*) plate_cascade)->detectMultiScale(openclFrame, plates, 1.1, 3, 0, minSize, maxSize); + } + else + { - plate_cascade->detectMultiScale( frame, plates, 1.1, 3, - 0, - //0|CV_HAAR_SCALE_IMAGE, - minSize, maxSize ); - } + plate_cascade->detectMultiScale( frame, plates, 1.1, 3, + 0, + //0|CV_HAAR_SCALE_IMAGE, + minSize, maxSize ); + } + if (config->debugTiming) + { + timespec endTime; + getTime(&endTime); + cout << "LBP Time: " << diffclock(startTime, endTime) << "ms." << endl; + } - if (config->debugTiming) - { - timespec endTime; - getTime(&endTime); - cout << "LBP Time: " << diffclock(startTime, endTime) << "ms." << endl; - } + for( int i = 0; i < plates.size(); i++ ) + { + plates[i].x = plates[i].x / scale_factor; + plates[i].y = plates[i].y / scale_factor; + plates[i].width = plates[i].width / scale_factor; + plates[i].height = plates[i].height / scale_factor; + } - - - for( int i = 0; i < plates.size(); i++ ) - { - plates[i].x = plates[i].x / scale_factor; - plates[i].y = plates[i].y / scale_factor; - plates[i].width = plates[i].width / scale_factor; - plates[i].height = plates[i].height / scale_factor; - } - - return plates; + return plates; } diff --git a/src/openalpr/simpleini/ConvertUTF.h b/src/openalpr/simpleini/ConvertUTF.h index 558383b..3149756 100644 --- a/src/openalpr/simpleini/ConvertUTF.h +++ b/src/openalpr/simpleini/ConvertUTF.h @@ -99,16 +99,18 @@ typedef unsigned char Boolean; /* 0 or 1 */ #define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF #define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF -typedef enum { - conversionOK, /* conversion successful */ - sourceExhausted, /* partial character in source, but hit end */ - targetExhausted, /* insuff. room in target for conversion */ - sourceIllegal /* source sequence is illegal/malformed */ +typedef enum +{ + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ } ConversionResult; -typedef enum { - strictConversion = 0, - lenientConversion +typedef enum +{ + strictConversion = 0, + lenientConversion } ConversionFlags; /* This is for C++ and does no harm in C */ @@ -117,28 +119,28 @@ extern "C" { #endif ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF8toUTF32 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF32toUTF8 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF16toUTF32 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF32toUTF16 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); diff --git a/src/openalpr/simpleini/simpleini.h b/src/openalpr/simpleini/simpleini.h index 41d8907..25cf2bf 100644 --- a/src/openalpr/simpleini/simpleini.h +++ b/src/openalpr/simpleini/simpleini.h @@ -233,15 +233,16 @@ # define SI_ASSERT(x) #endif -enum SI_Error { - SI_OK = 0, //!< No error - SI_UPDATED = 1, //!< An existing value was updated - SI_INSERTED = 2, //!< A new value was inserted +enum SI_Error +{ + SI_OK = 0, //!< No error + SI_UPDATED = 1, //!< An existing value was updated + SI_INSERTED = 2, //!< A new value was inserted - // note: test for any error with (retval < 0) - SI_FAIL = -1, //!< Generic failure - SI_NOMEM = -2, //!< Out of memory error - SI_FILE = -3 //!< File error (see errno for detail error) + // note: test for any error with (retval < 0) + SI_FAIL = -1, //!< Generic failure + SI_NOMEM = -2, //!< Out of memory error + SI_FILE = -3 //!< File error (see errno for detail error) }; #define SI_UTF8_SIGNATURE "\xEF\xBB\xBF" @@ -293,56 +294,72 @@ enum SI_Error { template class CSimpleIniTempl { -public: + public: typedef SI_CHAR SI_CHAR_T; /** key entry */ - struct Entry { - const SI_CHAR * pItem; - const SI_CHAR * pComment; - int nOrder; + struct Entry + { + const SI_CHAR * pItem; + const SI_CHAR * pComment; + int nOrder; - Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0) - : pItem(a_pszItem) - , pComment(NULL) - , nOrder(a_nOrder) - { } - Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder) - : pItem(a_pszItem) - , pComment(a_pszComment) - , nOrder(a_nOrder) - { } - Entry(const Entry & rhs) { operator=(rhs); } - Entry & operator=(const Entry & rhs) { - pItem = rhs.pItem; - pComment = rhs.pComment; - nOrder = rhs.nOrder; - return *this; - } + Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0) + : pItem(a_pszItem) + , pComment(NULL) + , nOrder(a_nOrder) + { } + Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder) + : pItem(a_pszItem) + , pComment(a_pszComment) + , nOrder(a_nOrder) + { } + Entry(const Entry & rhs) + { + operator=(rhs); + } + Entry & operator=(const Entry & rhs) + { + pItem = rhs.pItem; + pComment = rhs.pComment; + nOrder = rhs.nOrder; + return *this; + } #if defined(_MSC_VER) && _MSC_VER <= 1200 - /** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */ - bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); } - bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); } + /** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */ + bool operator<(const Entry & rhs) const + { + return LoadOrder()(*this, rhs); + } + bool operator>(const Entry & rhs) const + { + return LoadOrder()(rhs, *this); + } #endif - /** Strict less ordering by name of key only */ - struct KeyOrder : std::binary_function { - bool operator()(const Entry & lhs, const Entry & rhs) const { - const static SI_STRLESS isLess = SI_STRLESS(); - return isLess(lhs.pItem, rhs.pItem); - } - }; + /** Strict less ordering by name of key only */ + struct KeyOrder : std::binary_function + { + bool operator()(const Entry & lhs, const Entry & rhs) const + { + const static SI_STRLESS isLess = SI_STRLESS(); + return isLess(lhs.pItem, rhs.pItem); + } + }; - /** Strict less ordering by order, and then name of key */ - struct LoadOrder : std::binary_function { - bool operator()(const Entry & lhs, const Entry & rhs) const { - if (lhs.nOrder != rhs.nOrder) { - return lhs.nOrder < rhs.nOrder; - } - return KeyOrder()(lhs.pItem, rhs.pItem); - } - }; + /** Strict less ordering by order, and then name of key */ + struct LoadOrder : std::binary_function + { + bool operator()(const Entry & lhs, const Entry & rhs) const + { + if (lhs.nOrder != rhs.nOrder) + { + return lhs.nOrder < rhs.nOrder; + } + return KeyOrder()(lhs.pItem, rhs.pItem); + } + }; }; /** map keys to values */ @@ -359,52 +376,59 @@ public: /** interface definition for the OutputWriter object to pass to Save() in order to output the INI file data. */ - class OutputWriter { - public: + class OutputWriter + { + public: OutputWriter() { } virtual ~OutputWriter() { } virtual void Write(const char * a_pBuf) = 0; - private: + private: OutputWriter(const OutputWriter &); // disable OutputWriter & operator=(const OutputWriter &); // disable }; /** OutputWriter class to write the INI data to a file */ - class FileWriter : public OutputWriter { + class FileWriter : public OutputWriter + { FILE * m_file; - public: + public: FileWriter(FILE * a_file) : m_file(a_file) { } - void Write(const char * a_pBuf) { - fputs(a_pBuf, m_file); + void Write(const char * a_pBuf) + { + fputs(a_pBuf, m_file); } - private: + private: FileWriter(const FileWriter &); // disable FileWriter & operator=(const FileWriter &); // disable }; /** OutputWriter class to write the INI data to a string */ - class StringWriter : public OutputWriter { + class StringWriter : public OutputWriter + { std::string & m_string; - public: + public: StringWriter(std::string & a_string) : m_string(a_string) { } - void Write(const char * a_pBuf) { - m_string.append(a_pBuf); + void Write(const char * a_pBuf) + { + m_string.append(a_pBuf); } - private: + private: StringWriter(const StringWriter &); // disable StringWriter & operator=(const StringWriter &); // disable }; #ifdef SI_SUPPORT_IOSTREAMS /** OutputWriter class to write the INI data to an ostream */ - class StreamWriter : public OutputWriter { + class StreamWriter : public OutputWriter + { std::ostream & m_ostream; - public: + public: StreamWriter(std::ostream & a_ostream) : m_ostream(a_ostream) { } - void Write(const char * a_pBuf) { - m_ostream << a_pBuf; + void Write(const char * a_pBuf) + { + m_ostream << a_pBuf; } - private: + private: StreamWriter(const StreamWriter &); // disable StreamWriter & operator=(const StreamWriter &); // disable }; @@ -413,36 +437,48 @@ public: /** Characterset conversion utility class to convert strings to the same format as is used for the storage. */ - class Converter : private SI_CONVERTER { - public: + class Converter : private SI_CONVERTER + { + public: using SI_CONVERTER::SizeToStore; - Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) { - m_scratch.resize(1024); + Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) + { + m_scratch.resize(1024); } - Converter(const Converter & rhs) { operator=(rhs); } - Converter & operator=(const Converter & rhs) { - m_scratch = rhs.m_scratch; - return *this; + Converter(const Converter & rhs) + { + operator=(rhs); } - bool ConvertToStore(const SI_CHAR * a_pszString) { - size_t uLen = SizeToStore(a_pszString); - if (uLen == (size_t)(-1)) { - return false; - } - while (uLen > m_scratch.size()) { - m_scratch.resize(m_scratch.size() * 2); - } - return SI_CONVERTER::ConvertToStore( - a_pszString, - const_cast(m_scratch.data()), - m_scratch.size()); + Converter & operator=(const Converter & rhs) + { + m_scratch = rhs.m_scratch; + return *this; } - const char * Data() { return m_scratch.data(); } - private: + bool ConvertToStore(const SI_CHAR * a_pszString) + { + size_t uLen = SizeToStore(a_pszString); + if (uLen == (size_t)(-1)) + { + return false; + } + while (uLen > m_scratch.size()) + { + m_scratch.resize(m_scratch.size() * 2); + } + return SI_CONVERTER::ConvertToStore( + a_pszString, + const_cast(m_scratch.data()), + m_scratch.size()); + } + const char * Data() + { + return m_scratch.data(); + } + private: std::string m_scratch; }; -public: + public: /*-----------------------------------------------------------------------*/ /** Default constructor. @@ -452,10 +488,10 @@ public: @param a_bMultiLine See the method SetMultiLine() for details. */ CSimpleIniTempl( - bool a_bIsUtf8 = false, - bool a_bMultiKey = false, - bool a_bMultiLine = false - ); + bool a_bIsUtf8 = false, + bool a_bMultiKey = false, + bool a_bMultiLine = false + ); /** Destructor */ ~CSimpleIniTempl(); @@ -464,7 +500,10 @@ public: void Reset(); /** Has any data been loaded */ - bool IsEmpty() const { return m_data.empty(); } + bool IsEmpty() const + { + return m_data.empty(); + } /*-----------------------------------------------------------------------*/ /** @{ @name Settings */ @@ -483,12 +522,16 @@ public: \param a_bIsUtf8 Assume UTF-8 encoding for the source? */ - void SetUnicode(bool a_bIsUtf8 = true) { - if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8; + void SetUnicode(bool a_bIsUtf8 = true) + { + if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8; } /** Get the storage format of the INI data. */ - bool IsUnicode() const { return m_bStoreIsUtf8; } + bool IsUnicode() const + { + return m_bStoreIsUtf8; + } /** Should multiple identical keys be permitted in the file. If set to false then the last value encountered will be used as the value of the key. @@ -508,12 +551,16 @@ public: \param a_bAllowMultiKey Allow multi-keys in the source? */ - void SetMultiKey(bool a_bAllowMultiKey = true) { - m_bAllowMultiKey = a_bAllowMultiKey; + void SetMultiKey(bool a_bAllowMultiKey = true) + { + m_bAllowMultiKey = a_bAllowMultiKey; } /** Get the storage format of the INI data. */ - bool IsMultiKey() const { return m_bAllowMultiKey; } + bool IsMultiKey() const + { + return m_bAllowMultiKey; + } /** Should data values be permitted to span multiple lines in the file. If set to false then the multi-line construct <<=0 Number of keys in the section */ int GetSectionSize( - const SI_CHAR * a_pSection - ) const; + const SI_CHAR * a_pSection + ) const; /** Retrieve all key and value pairs for a section. The data is returned as a pointer to an STL map and can be iterated or searched as @@ -842,8 +898,8 @@ public: name found. */ const TKeyVal * GetSection( - const SI_CHAR * a_pSection - ) const; + const SI_CHAR * a_pSection + ) const; /** Retrieve the value for a specific key. If multiple keys are enabled (see SetMultiKey) then only the first value associated with that key @@ -863,11 +919,11 @@ public: @return other Value of the key */ const SI_CHAR * GetValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - const SI_CHAR * a_pDefault = NULL, - bool * a_pHasMultiple = NULL - ) const; + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pDefault = NULL, + bool * a_pHasMultiple = NULL + ) const; /** Retrieve a numeric value for a specific key. If multiple keys are enabled (see SetMultiKey) then only the first value associated with that key @@ -883,11 +939,11 @@ public: @return other Value of the key */ long GetLongValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - long a_nDefault = 0, - bool * a_pHasMultiple = NULL - ) const; + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nDefault = 0, + bool * a_pHasMultiple = NULL + ) const; /** Retrieve a numeric value for a specific key. If multiple keys are enabled (see SetMultiKey) then only the first value associated with that key @@ -903,11 +959,11 @@ public: @return other Value of the key */ double GetDoubleValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - double a_nDefault = 0, - bool * a_pHasMultiple = NULL - ) const; + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nDefault = 0, + bool * a_pHasMultiple = NULL + ) const; /** Retrieve a boolean value for a specific key. If multiple keys are enabled (see SetMultiKey) then only the first value associated with that key @@ -928,11 +984,11 @@ public: @return other Value of the key */ bool GetBoolValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - bool a_bDefault = false, - bool * a_pHasMultiple = NULL - ) const; + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bDefault = false, + bool * a_pHasMultiple = NULL + ) const; /** Add or update a section or value. This will always insert when multiple keys are enabled. @@ -964,14 +1020,14 @@ public: @return SI_INSERTED Value was inserted */ SI_Error SetValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - const SI_CHAR * a_pValue, - const SI_CHAR * a_pComment = NULL, - bool a_bForceReplace = false - ) + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ) { - return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true); + return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true); } /** Add or update a numeric value. This will always insert @@ -998,13 +1054,13 @@ public: @return SI_INSERTED Value was inserted */ SI_Error SetLongValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - long a_nValue, - const SI_CHAR * a_pComment = NULL, - bool a_bUseHex = false, - bool a_bForceReplace = false - ); + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nValue, + const SI_CHAR * a_pComment = NULL, + bool a_bUseHex = false, + bool a_bForceReplace = false + ); /** Add or update a double value. This will always insert when multiple keys are enabled. @@ -1027,12 +1083,12 @@ public: @return SI_INSERTED Value was inserted */ SI_Error SetDoubleValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - double a_nValue, - const SI_CHAR * a_pComment = NULL, - bool a_bForceReplace = false - ); + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ); /** Add or update a boolean value. This will always insert when multiple keys are enabled. @@ -1055,12 +1111,12 @@ public: @return SI_INSERTED Value was inserted */ SI_Error SetBoolValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - bool a_bValue, - const SI_CHAR * a_pComment = NULL, - bool a_bForceReplace = false - ); + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bValue, + const SI_CHAR * a_pComment = NULL, + bool a_bForceReplace = false + ); /** Delete an entire section, or a key from a section. Note that the data returned by GetSection is invalid and must not be used after @@ -1081,10 +1137,10 @@ public: @return false Key or section was not found. */ bool Delete( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - bool a_bRemoveEmpty = false - ); + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bRemoveEmpty = false + ); /*-----------------------------------------------------------------------*/ /** @} @@ -1095,14 +1151,15 @@ public: Use this to prepare the strings that you wish to append or prepend to the output INI data. */ - Converter GetConverter() const { - return Converter(m_bStoreIsUtf8); + Converter GetConverter() const + { + return Converter(m_bStoreIsUtf8); } /*-----------------------------------------------------------------------*/ /** @} */ -private: + private: // copying is not permitted CSimpleIniTempl(const CSimpleIniTempl &); // disabled CSimpleIniTempl & operator=(const CSimpleIniTempl &); // disabled @@ -1110,21 +1167,21 @@ private: /** Parse the data looking for a file comment and store it if found. */ SI_Error FindFileComment( - SI_CHAR *& a_pData, - bool a_bCopyStrings - ); + SI_CHAR *& a_pData, + bool a_bCopyStrings + ); /** Parse the data looking for the next valid entry. The memory pointed to by a_pData is modified by inserting NULL characters. The pointer is updated to the current location in the block of text. */ bool FindEntry( - SI_CHAR *& a_pData, - const SI_CHAR *& a_pSection, - const SI_CHAR *& a_pKey, - const SI_CHAR *& a_pVal, - const SI_CHAR *& a_pComment - ) const; + SI_CHAR *& a_pData, + const SI_CHAR *& a_pSection, + const SI_CHAR *& a_pKey, + const SI_CHAR *& a_pVal, + const SI_CHAR *& a_pComment + ) const; /** Add the section/key/value to our data. @@ -1149,28 +1206,31 @@ private: If false then the pointers will be used as is. */ SI_Error AddEntry( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - const SI_CHAR * a_pValue, - const SI_CHAR * a_pComment, - bool a_bForceReplace, - bool a_bCopyStrings - ); + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace, + bool a_bCopyStrings + ); /** Is the supplied character a whitespace character? */ - inline bool IsSpace(SI_CHAR ch) const { - return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'); + inline bool IsSpace(SI_CHAR ch) const + { + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'); } /** Does the supplied character start a comment line? */ - inline bool IsComment(SI_CHAR ch) const { - return (ch == ';' || ch == '#'); + inline bool IsComment(SI_CHAR ch) const + { + return (ch == ';' || ch == '#'); } /** Skip over a newline character (or characters) for either DOS or UNIX */ - inline void SkipNewLine(SI_CHAR *& a_pData) const { - a_pData += (*a_pData == '\r' && *(a_pData+1) == '\n') ? 2 : 1; + inline void SkipNewLine(SI_CHAR *& a_pData) const + { + a_pData += (*a_pData == '\r' && *(a_pData+1) == '\n') ? 2 : 1; } /** Make a copy of the supplied string, replacing the original pointer */ @@ -1180,28 +1240,29 @@ private: void DeleteString(const SI_CHAR * a_pString); /** Internal use of our string comparison function */ - bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const { - const static SI_STRLESS isLess = SI_STRLESS(); - return isLess(a_pLeft, a_pRight); + bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const + { + const static SI_STRLESS isLess = SI_STRLESS(); + return isLess(a_pLeft, a_pRight); } bool IsMultiLineTag(const SI_CHAR * a_pData) const; bool IsMultiLineData(const SI_CHAR * a_pData) const; bool LoadMultiLineText( - SI_CHAR *& a_pData, - const SI_CHAR *& a_pVal, - const SI_CHAR * a_pTagName, - bool a_bAllowBlankLinesInComment = false - ) const; + SI_CHAR *& a_pData, + const SI_CHAR *& a_pVal, + const SI_CHAR * a_pTagName, + bool a_bAllowBlankLinesInComment = false + ) const; bool IsNewLineChar(SI_CHAR a_c) const; bool OutputMultiLineText( - OutputWriter & a_oOutput, - Converter & a_oConverter, - const SI_CHAR * a_pText - ) const; + OutputWriter & a_oOutput, + Converter & a_oConverter, + const SI_CHAR * a_pText + ) const; -private: + private: /** Copy of the INI file data in our character format. This will be modified when parsed to have NULL characters added after all interesting string entries. All of the string pointers to sections, @@ -1251,10 +1312,10 @@ private: template CSimpleIniTempl::CSimpleIniTempl( - bool a_bIsUtf8, - bool a_bAllowMultiKey, - bool a_bAllowMultiLine - ) + bool a_bIsUtf8, + bool a_bAllowMultiKey, + bool a_bAllowMultiLine +) : m_pData(0) , m_uDataLen(0) , m_pFileComment(NULL) @@ -1268,74 +1329,77 @@ CSimpleIniTempl::CSimpleIniTempl( template CSimpleIniTempl::~CSimpleIniTempl() { - Reset(); + Reset(); } template void CSimpleIniTempl::Reset() { - // remove all data - delete[] m_pData; - m_pData = NULL; - m_uDataLen = 0; - m_pFileComment = NULL; - if (!m_data.empty()) { - m_data.erase(m_data.begin(), m_data.end()); - } - - // remove all strings - if (!m_strings.empty()) { - typename TNamesDepend::iterator i = m_strings.begin(); - for (; i != m_strings.end(); ++i) { - delete[] const_cast(i->pItem); - } - m_strings.erase(m_strings.begin(), m_strings.end()); + // remove all data + delete[] m_pData; + m_pData = NULL; + m_uDataLen = 0; + m_pFileComment = NULL; + if (!m_data.empty()) + { + m_data.erase(m_data.begin(), m_data.end()); + } + // remove all strings + if (!m_strings.empty()) + { + typename TNamesDepend::iterator i = m_strings.begin(); + for (; i != m_strings.end(); ++i) + { + delete[] const_cast(i->pItem); } + m_strings.erase(m_strings.begin(), m_strings.end()); + } } template SI_Error CSimpleIniTempl::LoadFile( - const char * a_pszFile - ) + const char * a_pszFile +) { - FILE * fp = NULL; + FILE * fp = NULL; #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE - fopen_s(&fp, a_pszFile, "rb"); + fopen_s(&fp, a_pszFile, "rb"); #else // !__STDC_WANT_SECURE_LIB__ - fp = fopen(a_pszFile, "rb"); + fp = fopen(a_pszFile, "rb"); #endif // __STDC_WANT_SECURE_LIB__ - if (!fp) { - return SI_FILE; - } - SI_Error rc = LoadFile(fp); - fclose(fp); - return rc; + if (!fp) + { + return SI_FILE; + } + SI_Error rc = LoadFile(fp); + fclose(fp); + return rc; } #ifdef SI_HAS_WIDE_FILE template SI_Error CSimpleIniTempl::LoadFile( - const SI_WCHAR_T * a_pwszFile - ) + const SI_WCHAR_T * a_pwszFile +) { #ifdef _WIN32 - FILE * fp = NULL; + FILE * fp = NULL; #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE - _wfopen_s(&fp, a_pwszFile, L"rb"); + _wfopen_s(&fp, a_pwszFile, L"rb"); #else // !__STDC_WANT_SECURE_LIB__ - fp = _wfopen(a_pwszFile, L"rb"); + fp = _wfopen(a_pwszFile, L"rb"); #endif // __STDC_WANT_SECURE_LIB__ - if (!fp) return SI_FILE; - SI_Error rc = LoadFile(fp); - fclose(fp); - return rc; + if (!fp) return SI_FILE; + SI_Error rc = LoadFile(fp); + fclose(fp); + return rc; #else // !_WIN32 (therefore SI_CONVERT_ICU) - char szFile[256]; - u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); - return LoadFile(szFile); + char szFile[256]; + u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); + return LoadFile(szFile); #endif // _WIN32 } #endif // SI_HAS_WIDE_FILE @@ -1343,1014 +1407,1023 @@ CSimpleIniTempl::LoadFile( template SI_Error CSimpleIniTempl::LoadFile( - FILE * a_fpFile - ) + FILE * a_fpFile +) { - // load the raw file data - int retval = fseek(a_fpFile, 0, SEEK_END); - if (retval != 0) { - return SI_FILE; - } - long lSize = ftell(a_fpFile); - if (lSize < 0) { - return SI_FILE; - } - if (lSize == 0) { - return SI_OK; - } - - // allocate and ensure NULL terminated - char * pData = new char[lSize+1]; - if (!pData) { - return SI_NOMEM; - } - pData[lSize] = 0; - - // load data into buffer - fseek(a_fpFile, 0, SEEK_SET); - size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile); - if (uRead != (size_t) lSize) { - delete[] pData; - return SI_FILE; - } - - // convert the raw data to unicode - SI_Error rc = LoadData(pData, uRead); + // load the raw file data + int retval = fseek(a_fpFile, 0, SEEK_END); + if (retval != 0) + { + return SI_FILE; + } + long lSize = ftell(a_fpFile); + if (lSize < 0) + { + return SI_FILE; + } + if (lSize == 0) + { + return SI_OK; + } + // allocate and ensure NULL terminated + char * pData = new char[lSize+1]; + if (!pData) + { + return SI_NOMEM; + } + pData[lSize] = 0; + // load data into buffer + fseek(a_fpFile, 0, SEEK_SET); + size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile); + if (uRead != (size_t) lSize) + { delete[] pData; - return rc; + return SI_FILE; + } + // convert the raw data to unicode + SI_Error rc = LoadData(pData, uRead); + delete[] pData; + return rc; } template SI_Error CSimpleIniTempl::LoadData( - const char * a_pData, - size_t a_uDataLen - ) + const char * a_pData, + size_t a_uDataLen +) { - SI_CONVERTER converter(m_bStoreIsUtf8); - - if (a_uDataLen == 0) { - return SI_OK; - } - - // consume the UTF-8 BOM if it exists - if (m_bStoreIsUtf8 && a_uDataLen >= 3) { - if (memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) { - a_pData += 3; - a_uDataLen -= 3; - } - } - - // determine the length of the converted data - size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen); - if (uLen == (size_t)(-1)) { - return SI_FAIL; - } - - // allocate memory for the data, ensure that there is a NULL - // terminator wherever the converted data ends - SI_CHAR * pData = new SI_CHAR[uLen+1]; - if (!pData) { - return SI_NOMEM; - } - memset(pData, 0, sizeof(SI_CHAR)*(uLen+1)); - - // convert the data - if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) { - delete[] pData; - return SI_FAIL; - } - - // parse it - const static SI_CHAR empty = 0; - SI_CHAR * pWork = pData; - const SI_CHAR * pSection = ∅ - const SI_CHAR * pItem = NULL; - const SI_CHAR * pVal = NULL; - const SI_CHAR * pComment = NULL; - - // We copy the strings if we are loading data into this class when we - // already have stored some. - bool bCopyStrings = (m_pData != NULL); - - // find a file comment if it exists, this is a comment that starts at the - // beginning of the file and continues until the first blank line. - SI_Error rc = FindFileComment(pWork, bCopyStrings); - if (rc < 0) return rc; - - // add every entry in the file to the data table - while (FindEntry(pWork, pSection, pItem, pVal, pComment)) { - rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings); - if (rc < 0) return rc; - } - - // store these strings if we didn't copy them - if (bCopyStrings) { - delete[] pData; - } - else { - m_pData = pData; - m_uDataLen = uLen+1; - } - + SI_CONVERTER converter(m_bStoreIsUtf8); + if (a_uDataLen == 0) + { return SI_OK; + } + // consume the UTF-8 BOM if it exists + if (m_bStoreIsUtf8 && a_uDataLen >= 3) + { + if (memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) + { + a_pData += 3; + a_uDataLen -= 3; + } + } + // determine the length of the converted data + size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen); + if (uLen == (size_t)(-1)) + { + return SI_FAIL; + } + // allocate memory for the data, ensure that there is a NULL + // terminator wherever the converted data ends + SI_CHAR * pData = new SI_CHAR[uLen+1]; + if (!pData) + { + return SI_NOMEM; + } + memset(pData, 0, sizeof(SI_CHAR)*(uLen+1)); + // convert the data + if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) + { + delete[] pData; + return SI_FAIL; + } + // parse it + const static SI_CHAR empty = 0; + SI_CHAR * pWork = pData; + const SI_CHAR * pSection = ∅ + const SI_CHAR * pItem = NULL; + const SI_CHAR * pVal = NULL; + const SI_CHAR * pComment = NULL; + // We copy the strings if we are loading data into this class when we + // already have stored some. + bool bCopyStrings = (m_pData != NULL); + // find a file comment if it exists, this is a comment that starts at the + // beginning of the file and continues until the first blank line. + SI_Error rc = FindFileComment(pWork, bCopyStrings); + if (rc < 0) return rc; + // add every entry in the file to the data table + while (FindEntry(pWork, pSection, pItem, pVal, pComment)) + { + rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings); + if (rc < 0) return rc; + } + // store these strings if we didn't copy them + if (bCopyStrings) + { + delete[] pData; + } + else + { + m_pData = pData; + m_uDataLen = uLen+1; + } + return SI_OK; } #ifdef SI_SUPPORT_IOSTREAMS template SI_Error CSimpleIniTempl::LoadData( - std::istream & a_istream - ) + std::istream & a_istream +) { - std::string strData; - char szBuf[512]; - do { - a_istream.get(szBuf, sizeof(szBuf), '\0'); - strData.append(szBuf); - } - while (a_istream.good()); - return LoadData(strData); + std::string strData; + char szBuf[512]; + do + { + a_istream.get(szBuf, sizeof(szBuf), '\0'); + strData.append(szBuf); + } + while (a_istream.good()); + return LoadData(strData); } #endif // SI_SUPPORT_IOSTREAMS template SI_Error CSimpleIniTempl::FindFileComment( - SI_CHAR *& a_pData, - bool a_bCopyStrings - ) + SI_CHAR *& a_pData, + bool a_bCopyStrings +) { - // there can only be a single file comment - if (m_pFileComment) { - return SI_OK; - } - - // Load the file comment as multi-line text, this will modify all of - // the newline characters to be single \n chars - if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) { - return SI_OK; - } - - // copy the string if necessary - if (a_bCopyStrings) { - SI_Error rc = CopyString(m_pFileComment); - if (rc < 0) return rc; - } - + // there can only be a single file comment + if (m_pFileComment) + { return SI_OK; + } + // Load the file comment as multi-line text, this will modify all of + // the newline characters to be single \n chars + if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) + { + return SI_OK; + } + // copy the string if necessary + if (a_bCopyStrings) + { + SI_Error rc = CopyString(m_pFileComment); + if (rc < 0) return rc; + } + return SI_OK; } template bool CSimpleIniTempl::FindEntry( - SI_CHAR *& a_pData, - const SI_CHAR *& a_pSection, - const SI_CHAR *& a_pKey, - const SI_CHAR *& a_pVal, - const SI_CHAR *& a_pComment - ) const + SI_CHAR *& a_pData, + const SI_CHAR *& a_pSection, + const SI_CHAR *& a_pKey, + const SI_CHAR *& a_pVal, + const SI_CHAR *& a_pComment +) const { - a_pComment = NULL; - - SI_CHAR * pTrail = NULL; - while (*a_pData) { - // skip spaces and empty lines - while (*a_pData && IsSpace(*a_pData)) { - ++a_pData; - } - if (!*a_pData) { - break; - } - - // skip processing of comment lines but keep a pointer to - // the start of the comment. - if (IsComment(*a_pData)) { - LoadMultiLineText(a_pData, a_pComment, NULL, true); - continue; - } - - // process section names - if (*a_pData == '[') { - // skip leading spaces - ++a_pData; - while (*a_pData && IsSpace(*a_pData)) { - ++a_pData; - } - - // find the end of the section name (it may contain spaces) - // and convert it to lowercase as necessary - a_pSection = a_pData; - while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) { - ++a_pData; - } - - // if it's an invalid line, just skip it - if (*a_pData != ']') { - continue; - } - - // remove trailing spaces from the section - pTrail = a_pData - 1; - while (pTrail >= a_pSection && IsSpace(*pTrail)) { - --pTrail; - } - ++pTrail; - *pTrail = 0; - - // skip to the end of the line - ++a_pData; // safe as checked that it == ']' above - while (*a_pData && !IsNewLineChar(*a_pData)) { - ++a_pData; - } - - a_pKey = NULL; - a_pVal = NULL; - return true; - } - - // find the end of the key name (it may contain spaces) - // and convert it to lowercase as necessary - a_pKey = a_pData; - while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) { - ++a_pData; - } - - // if it's an invalid line, just skip it - if (*a_pData != '=') { - continue; - } - - // empty keys are invalid - if (a_pKey == a_pData) { - while (*a_pData && !IsNewLineChar(*a_pData)) { - ++a_pData; - } - continue; - } - - // remove trailing spaces from the key - pTrail = a_pData - 1; - while (pTrail >= a_pKey && IsSpace(*pTrail)) { - --pTrail; - } - ++pTrail; - *pTrail = 0; - - // skip leading whitespace on the value - ++a_pData; // safe as checked that it == '=' above - while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) { - ++a_pData; - } - - // find the end of the value which is the end of this line - a_pVal = a_pData; - while (*a_pData && !IsNewLineChar(*a_pData)) { - ++a_pData; - } - - // remove trailing spaces from the value - pTrail = a_pData - 1; - if (*a_pData) { // prepare for the next round - SkipNewLine(a_pData); - } - while (pTrail >= a_pVal && IsSpace(*pTrail)) { - --pTrail; - } - ++pTrail; - *pTrail = 0; - - // check for multi-line entries - if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) { - // skip the "<<<" to get the tag that will end the multiline - const SI_CHAR * pTagName = a_pVal + 3; - return LoadMultiLineText(a_pData, a_pVal, pTagName); - } - - // return the standard entry - return true; + a_pComment = NULL; + SI_CHAR * pTrail = NULL; + while (*a_pData) + { + // skip spaces and empty lines + while (*a_pData && IsSpace(*a_pData)) + { + ++a_pData; } - - return false; + if (!*a_pData) + { + break; + } + // skip processing of comment lines but keep a pointer to + // the start of the comment. + if (IsComment(*a_pData)) + { + LoadMultiLineText(a_pData, a_pComment, NULL, true); + continue; + } + // process section names + if (*a_pData == '[') + { + // skip leading spaces + ++a_pData; + while (*a_pData && IsSpace(*a_pData)) + { + ++a_pData; + } + // find the end of the section name (it may contain spaces) + // and convert it to lowercase as necessary + a_pSection = a_pData; + while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) + { + ++a_pData; + } + // if it's an invalid line, just skip it + if (*a_pData != ']') + { + continue; + } + // remove trailing spaces from the section + pTrail = a_pData - 1; + while (pTrail >= a_pSection && IsSpace(*pTrail)) + { + --pTrail; + } + ++pTrail; + *pTrail = 0; + // skip to the end of the line + ++a_pData; // safe as checked that it == ']' above + while (*a_pData && !IsNewLineChar(*a_pData)) + { + ++a_pData; + } + a_pKey = NULL; + a_pVal = NULL; + return true; + } + // find the end of the key name (it may contain spaces) + // and convert it to lowercase as necessary + a_pKey = a_pData; + while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) + { + ++a_pData; + } + // if it's an invalid line, just skip it + if (*a_pData != '=') + { + continue; + } + // empty keys are invalid + if (a_pKey == a_pData) + { + while (*a_pData && !IsNewLineChar(*a_pData)) + { + ++a_pData; + } + continue; + } + // remove trailing spaces from the key + pTrail = a_pData - 1; + while (pTrail >= a_pKey && IsSpace(*pTrail)) + { + --pTrail; + } + ++pTrail; + *pTrail = 0; + // skip leading whitespace on the value + ++a_pData; // safe as checked that it == '=' above + while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) + { + ++a_pData; + } + // find the end of the value which is the end of this line + a_pVal = a_pData; + while (*a_pData && !IsNewLineChar(*a_pData)) + { + ++a_pData; + } + // remove trailing spaces from the value + pTrail = a_pData - 1; + if (*a_pData) // prepare for the next round + { + SkipNewLine(a_pData); + } + while (pTrail >= a_pVal && IsSpace(*pTrail)) + { + --pTrail; + } + ++pTrail; + *pTrail = 0; + // check for multi-line entries + if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) + { + // skip the "<<<" to get the tag that will end the multiline + const SI_CHAR * pTagName = a_pVal + 3; + return LoadMultiLineText(a_pData, a_pVal, pTagName); + } + // return the standard entry + return true; + } + return false; } template bool CSimpleIniTempl::IsMultiLineTag( - const SI_CHAR * a_pVal - ) const + const SI_CHAR * a_pVal +) const { - // check for the "<<<" prefix for a multi-line entry - if (*a_pVal++ != '<') return false; - if (*a_pVal++ != '<') return false; - if (*a_pVal++ != '<') return false; - return true; + // check for the "<<<" prefix for a multi-line entry + if (*a_pVal++ != '<') return false; + if (*a_pVal++ != '<') return false; + if (*a_pVal++ != '<') return false; + return true; } template bool CSimpleIniTempl::IsMultiLineData( - const SI_CHAR * a_pData - ) const + const SI_CHAR * a_pData +) const { - // data is multi-line if it has any of the following features: - // * whitespace prefix - // * embedded newlines - // * whitespace suffix - - // empty string - if (!*a_pData) { - return false; - } - - // check for prefix - if (IsSpace(*a_pData)) { - return true; - } - - // embedded newlines - while (*a_pData) { - if (IsNewLineChar(*a_pData)) { - return true; - } - ++a_pData; - } - - // check for suffix - if (IsSpace(*--a_pData)) { - return true; - } - + // data is multi-line if it has any of the following features: + // * whitespace prefix + // * embedded newlines + // * whitespace suffix + // empty string + if (!*a_pData) + { return false; + } + // check for prefix + if (IsSpace(*a_pData)) + { + return true; + } + // embedded newlines + while (*a_pData) + { + if (IsNewLineChar(*a_pData)) + { + return true; + } + ++a_pData; + } + // check for suffix + if (IsSpace(*--a_pData)) + { + return true; + } + return false; } template bool CSimpleIniTempl::IsNewLineChar( - SI_CHAR a_c - ) const + SI_CHAR a_c +) const { - return (a_c == '\n' || a_c == '\r'); + return (a_c == '\n' || a_c == '\r'); } template bool CSimpleIniTempl::LoadMultiLineText( - SI_CHAR *& a_pData, - const SI_CHAR *& a_pVal, - const SI_CHAR * a_pTagName, - bool a_bAllowBlankLinesInComment - ) const + SI_CHAR *& a_pData, + const SI_CHAR *& a_pVal, + const SI_CHAR * a_pTagName, + bool a_bAllowBlankLinesInComment +) const { - // we modify this data to strip all newlines down to a single '\n' - // character. This means that on Windows we need to strip out some - // characters which will make the data shorter. - // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become - // LINE1-LINE1\nLINE2-LINE2\0 - // The pDataLine entry is the pointer to the location in memory that - // the current line needs to start to run following the existing one. - // This may be the same as pCurrLine in which case no move is needed. - SI_CHAR * pDataLine = a_pData; - SI_CHAR * pCurrLine; - - // value starts at the current line - a_pVal = a_pData; - - // find the end tag. This tag must start in column 1 and be - // followed by a newline. No whitespace removal is done while - // searching for this tag. - SI_CHAR cEndOfLineChar = *a_pData; - for(;;) { - // if we are loading comments then we need a comment character as - // the first character on every line - if (!a_pTagName && !IsComment(*a_pData)) { - // if we aren't allowing blank lines then we're done - if (!a_bAllowBlankLinesInComment) { - break; - } - - // if we are allowing blank lines then we only include them - // in this comment if another comment follows, so read ahead - // to find out. - SI_CHAR * pCurr = a_pData; - int nNewLines = 0; - while (IsSpace(*pCurr)) { - if (IsNewLineChar(*pCurr)) { - ++nNewLines; - SkipNewLine(pCurr); - } - else { - ++pCurr; - } - } - - // we have a comment, add the blank lines to the output - // and continue processing from here - if (IsComment(*pCurr)) { - for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n'; - a_pData = pCurr; - continue; - } - - // the comment ends here - break; - } - - // find the end of this line - pCurrLine = a_pData; - while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData; - - // move this line down to the location that it should be if necessary - if (pDataLine < pCurrLine) { - size_t nLen = (size_t) (a_pData - pCurrLine); - memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR)); - pDataLine[nLen] = '\0'; - } - - // end the line with a NULL - cEndOfLineChar = *a_pData; - *a_pData = 0; - - // if are looking for a tag then do the check now. This is done before - // checking for end of the data, so that if we have the tag at the end - // of the data then the tag is removed correctly. - if (a_pTagName && - (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine))) + // we modify this data to strip all newlines down to a single '\n' + // character. This means that on Windows we need to strip out some + // characters which will make the data shorter. + // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become + // LINE1-LINE1\nLINE2-LINE2\0 + // The pDataLine entry is the pointer to the location in memory that + // the current line needs to start to run following the existing one. + // This may be the same as pCurrLine in which case no move is needed. + SI_CHAR * pDataLine = a_pData; + SI_CHAR * pCurrLine; + // value starts at the current line + a_pVal = a_pData; + // find the end tag. This tag must start in column 1 and be + // followed by a newline. No whitespace removal is done while + // searching for this tag. + SI_CHAR cEndOfLineChar = *a_pData; + for(;;) + { + // if we are loading comments then we need a comment character as + // the first character on every line + if (!a_pTagName && !IsComment(*a_pData)) + { + // if we aren't allowing blank lines then we're done + if (!a_bAllowBlankLinesInComment) + { + break; + } + // if we are allowing blank lines then we only include them + // in this comment if another comment follows, so read ahead + // to find out. + SI_CHAR * pCurr = a_pData; + int nNewLines = 0; + while (IsSpace(*pCurr)) + { + if (IsNewLineChar(*pCurr)) { - break; + ++nNewLines; + SkipNewLine(pCurr); } - - // if we are at the end of the data then we just automatically end - // this entry and return the current data. - if (!cEndOfLineChar) { - return true; + else + { + ++pCurr; } - - // otherwise we need to process this newline to ensure that it consists - // of just a single \n character. - pDataLine += (a_pData - pCurrLine); - *a_pData = cEndOfLineChar; - SkipNewLine(a_pData); - *pDataLine++ = '\n'; + } + // we have a comment, add the blank lines to the output + // and continue processing from here + if (IsComment(*pCurr)) + { + for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n'; + a_pData = pCurr; + continue; + } + // the comment ends here + break; } - - // if we didn't find a comment at all then return false - if (a_pVal == a_pData) { - a_pVal = NULL; - return false; + // find the end of this line + pCurrLine = a_pData; + while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData; + // move this line down to the location that it should be if necessary + if (pDataLine < pCurrLine) + { + size_t nLen = (size_t) (a_pData - pCurrLine); + memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR)); + pDataLine[nLen] = '\0'; } - - // the data (which ends at the end of the last line) needs to be - // null-terminated BEFORE before the newline character(s). If the - // user wants a new line in the multi-line data then they need to - // add an empty line before the tag. - *--pDataLine = '\0'; - - // if looking for a tag and if we aren't at the end of the data, - // then move a_pData to the start of the next line. - if (a_pTagName && cEndOfLineChar) { - SI_ASSERT(IsNewLineChar(cEndOfLineChar)); - *a_pData = cEndOfLineChar; - SkipNewLine(a_pData); + // end the line with a NULL + cEndOfLineChar = *a_pData; + *a_pData = 0; + // if are looking for a tag then do the check now. This is done before + // checking for end of the data, so that if we have the tag at the end + // of the data then the tag is removed correctly. + if (a_pTagName && + (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine))) + { + break; } - - return true; + // if we are at the end of the data then we just automatically end + // this entry and return the current data. + if (!cEndOfLineChar) + { + return true; + } + // otherwise we need to process this newline to ensure that it consists + // of just a single \n character. + pDataLine += (a_pData - pCurrLine); + *a_pData = cEndOfLineChar; + SkipNewLine(a_pData); + *pDataLine++ = '\n'; + } + // if we didn't find a comment at all then return false + if (a_pVal == a_pData) + { + a_pVal = NULL; + return false; + } + // the data (which ends at the end of the last line) needs to be + // null-terminated BEFORE before the newline character(s). If the + // user wants a new line in the multi-line data then they need to + // add an empty line before the tag. + *--pDataLine = '\0'; + // if looking for a tag and if we aren't at the end of the data, + // then move a_pData to the start of the next line. + if (a_pTagName && cEndOfLineChar) + { + SI_ASSERT(IsNewLineChar(cEndOfLineChar)); + *a_pData = cEndOfLineChar; + SkipNewLine(a_pData); + } + return true; } template SI_Error CSimpleIniTempl::CopyString( - const SI_CHAR *& a_pString - ) + const SI_CHAR *& a_pString +) { - size_t uLen = 0; - if (sizeof(SI_CHAR) == sizeof(char)) { - uLen = strlen((const char *)a_pString); - } - else if (sizeof(SI_CHAR) == sizeof(wchar_t)) { - uLen = wcslen((const wchar_t *)a_pString); - } - else { - for ( ; a_pString[uLen]; ++uLen) /*loop*/ ; - } - ++uLen; // NULL character - SI_CHAR * pCopy = new SI_CHAR[uLen]; - if (!pCopy) { - return SI_NOMEM; - } - memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen); - m_strings.push_back(pCopy); - a_pString = pCopy; - return SI_OK; + size_t uLen = 0; + if (sizeof(SI_CHAR) == sizeof(char)) + { + uLen = strlen((const char *)a_pString); + } + else if (sizeof(SI_CHAR) == sizeof(wchar_t)) + { + uLen = wcslen((const wchar_t *)a_pString); + } + else + { + for ( ; a_pString[uLen]; ++uLen) /*loop*/ ; + } + ++uLen; // NULL character + SI_CHAR * pCopy = new SI_CHAR[uLen]; + if (!pCopy) + { + return SI_NOMEM; + } + memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen); + m_strings.push_back(pCopy); + a_pString = pCopy; + return SI_OK; } template SI_Error CSimpleIniTempl::AddEntry( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - const SI_CHAR * a_pValue, - const SI_CHAR * a_pComment, - bool a_bForceReplace, - bool a_bCopyStrings - ) + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace, + bool a_bCopyStrings +) { - SI_Error rc; - bool bInserted = false; - - SI_ASSERT(!a_pComment || IsComment(*a_pComment)); - - // if we are copying strings then make a copy of the comment now - // because we will need it when we add the entry. - if (a_bCopyStrings && a_pComment) { - rc = CopyString(a_pComment); - if (rc < 0) return rc; + SI_Error rc; + bool bInserted = false; + SI_ASSERT(!a_pComment || IsComment(*a_pComment)); + // if we are copying strings then make a copy of the comment now + // because we will need it when we add the entry. + if (a_bCopyStrings && a_pComment) + { + rc = CopyString(a_pComment); + if (rc < 0) return rc; + } + // create the section entry if necessary + typename TSection::iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) + { + // if the section doesn't exist then we need a copy as the + // string needs to last beyond the end of this function + if (a_bCopyStrings) + { + rc = CopyString(a_pSection); + if (rc < 0) return rc; } - - // create the section entry if necessary - typename TSection::iterator iSection = m_data.find(a_pSection); - if (iSection == m_data.end()) { - // if the section doesn't exist then we need a copy as the - // string needs to last beyond the end of this function - if (a_bCopyStrings) { - rc = CopyString(a_pSection); - if (rc < 0) return rc; - } - - // only set the comment if this is a section only entry - Entry oSection(a_pSection, ++m_nOrder); - if (a_pComment && (!a_pKey || !a_pValue)) { - oSection.pComment = a_pComment; - } - - typename TSection::value_type oEntry(oSection, TKeyVal()); - typedef typename TSection::iterator SectionIterator; - std::pair i = m_data.insert(oEntry); - iSection = i.first; - bInserted = true; + // only set the comment if this is a section only entry + Entry oSection(a_pSection, ++m_nOrder); + if (a_pComment && (!a_pKey || !a_pValue)) + { + oSection.pComment = a_pComment; } - if (!a_pKey || !a_pValue) { - // section only entries are specified with pItem and pVal as NULL - return bInserted ? SI_INSERTED : SI_UPDATED; - } - - // check for existence of the key - TKeyVal & keyval = iSection->second; - typename TKeyVal::iterator iKey = keyval.find(a_pKey); - - // remove all existing entries but save the load order and - // comment of the first entry - int nLoadOrder = ++m_nOrder; - if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) { - const SI_CHAR * pComment = NULL; - while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) { - if (iKey->first.nOrder < nLoadOrder) { - nLoadOrder = iKey->first.nOrder; - pComment = iKey->first.pComment; - } - ++iKey; - } - if (pComment) { - DeleteString(a_pComment); - a_pComment = pComment; - CopyString(a_pComment); - } - Delete(a_pSection, a_pKey); - iKey = keyval.end(); - } - - // make string copies if necessary - bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace; - if (a_bCopyStrings) { - if (bForceCreateNewKey || iKey == keyval.end()) { - // if the key doesn't exist then we need a copy as the - // string needs to last beyond the end of this function - // because we will be inserting the key next - rc = CopyString(a_pKey); - if (rc < 0) return rc; - } - - // we always need a copy of the value - rc = CopyString(a_pValue); - if (rc < 0) return rc; - } - - // create the key entry - if (iKey == keyval.end() || bForceCreateNewKey) { - Entry oKey(a_pKey, nLoadOrder); - if (a_pComment) { - oKey.pComment = a_pComment; - } - typename TKeyVal::value_type oEntry(oKey, static_cast(NULL)); - iKey = keyval.insert(oEntry); - bInserted = true; - } - iKey->second = a_pValue; + typename TSection::value_type oEntry(oSection, TKeyVal()); + typedef typename TSection::iterator SectionIterator; + std::pair i = m_data.insert(oEntry); + iSection = i.first; + bInserted = true; + } + if (!a_pKey || !a_pValue) + { + // section only entries are specified with pItem and pVal as NULL return bInserted ? SI_INSERTED : SI_UPDATED; + } + // check for existence of the key + TKeyVal & keyval = iSection->second; + typename TKeyVal::iterator iKey = keyval.find(a_pKey); + // remove all existing entries but save the load order and + // comment of the first entry + int nLoadOrder = ++m_nOrder; + if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) + { + const SI_CHAR * pComment = NULL; + while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) + { + if (iKey->first.nOrder < nLoadOrder) + { + nLoadOrder = iKey->first.nOrder; + pComment = iKey->first.pComment; + } + ++iKey; + } + if (pComment) + { + DeleteString(a_pComment); + a_pComment = pComment; + CopyString(a_pComment); + } + Delete(a_pSection, a_pKey); + iKey = keyval.end(); + } + // make string copies if necessary + bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace; + if (a_bCopyStrings) + { + if (bForceCreateNewKey || iKey == keyval.end()) + { + // if the key doesn't exist then we need a copy as the + // string needs to last beyond the end of this function + // because we will be inserting the key next + rc = CopyString(a_pKey); + if (rc < 0) return rc; + } + // we always need a copy of the value + rc = CopyString(a_pValue); + if (rc < 0) return rc; + } + // create the key entry + if (iKey == keyval.end() || bForceCreateNewKey) + { + Entry oKey(a_pKey, nLoadOrder); + if (a_pComment) + { + oKey.pComment = a_pComment; + } + typename TKeyVal::value_type oEntry(oKey, static_cast(NULL)); + iKey = keyval.insert(oEntry); + bInserted = true; + } + iKey->second = a_pValue; + return bInserted ? SI_INSERTED : SI_UPDATED; } template const SI_CHAR * CSimpleIniTempl::GetValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - const SI_CHAR * a_pDefault, - bool * a_pHasMultiple - ) const + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + const SI_CHAR * a_pDefault, + bool * a_pHasMultiple +) const { - if (a_pHasMultiple) { - *a_pHasMultiple = false; + if (a_pHasMultiple) + { + *a_pHasMultiple = false; + } + if (!a_pSection || !a_pKey) + { + return a_pDefault; + } + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) + { + return a_pDefault; + } + typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) + { + return a_pDefault; + } + // check for multiple entries with the same key + if (m_bAllowMultiKey && a_pHasMultiple) + { + typename TKeyVal::const_iterator iTemp = iKeyVal; + if (++iTemp != iSection->second.end()) + { + if (!IsLess(a_pKey, iTemp->first.pItem)) + { + *a_pHasMultiple = true; + } } - if (!a_pSection || !a_pKey) { - return a_pDefault; - } - typename TSection::const_iterator iSection = m_data.find(a_pSection); - if (iSection == m_data.end()) { - return a_pDefault; - } - typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); - if (iKeyVal == iSection->second.end()) { - return a_pDefault; - } - - // check for multiple entries with the same key - if (m_bAllowMultiKey && a_pHasMultiple) { - typename TKeyVal::const_iterator iTemp = iKeyVal; - if (++iTemp != iSection->second.end()) { - if (!IsLess(a_pKey, iTemp->first.pItem)) { - *a_pHasMultiple = true; - } - } - } - - return iKeyVal->second; + } + return iKeyVal->second; } template long CSimpleIniTempl::GetLongValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - long a_nDefault, - bool * a_pHasMultiple - ) const + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nDefault, + bool * a_pHasMultiple +) const { - // return the default if we don't have a value - const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); - if (!pszValue || !*pszValue) return a_nDefault; - - // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII - char szValue[64] = { 0 }; - SI_CONVERTER c(m_bStoreIsUtf8); - if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) { - return a_nDefault; - } - - // handle the value as hex if prefaced with "0x" - long nValue = a_nDefault; - char * pszSuffix = szValue; - if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) { - if (!szValue[2]) return a_nDefault; - nValue = strtol(&szValue[2], &pszSuffix, 16); - } - else { - nValue = strtol(szValue, &pszSuffix, 10); - } - - // any invalid strings will return the default value - if (*pszSuffix) { - return a_nDefault; - } - - return nValue; + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_nDefault; + // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII + char szValue[64] = { 0 }; + SI_CONVERTER c(m_bStoreIsUtf8); + if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) + { + return a_nDefault; + } + // handle the value as hex if prefaced with "0x" + long nValue = a_nDefault; + char * pszSuffix = szValue; + if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) + { + if (!szValue[2]) return a_nDefault; + nValue = strtol(&szValue[2], &pszSuffix, 16); + } + else + { + nValue = strtol(szValue, &pszSuffix, 10); + } + // any invalid strings will return the default value + if (*pszSuffix) + { + return a_nDefault; + } + return nValue; } template SI_Error CSimpleIniTempl::SetLongValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - long a_nValue, - const SI_CHAR * a_pComment, - bool a_bUseHex, - bool a_bForceReplace - ) + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + long a_nValue, + const SI_CHAR * a_pComment, + bool a_bUseHex, + bool a_bForceReplace +) { - // use SetValue to create sections - if (!a_pSection || !a_pKey) return SI_FAIL; - - // convert to an ASCII string - char szInput[64]; + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + // convert to an ASCII string + char szInput[64]; #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE - sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); + sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); #else // !__STDC_WANT_SECURE_LIB__ - sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); + sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue); #endif // __STDC_WANT_SECURE_LIB__ - - // convert to output text - SI_CHAR szOutput[64]; - SI_CONVERTER c(m_bStoreIsUtf8); - c.ConvertFromStore(szInput, strlen(szInput) + 1, - szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); - - // actually add it - return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(szInput, strlen(szInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); } template double CSimpleIniTempl::GetDoubleValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - double a_nDefault, - bool * a_pHasMultiple - ) const + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nDefault, + bool * a_pHasMultiple +) const { - // return the default if we don't have a value - const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); - if (!pszValue || !*pszValue) return a_nDefault; - - // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII - char szValue[64] = { 0 }; - SI_CONVERTER c(m_bStoreIsUtf8); - if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) { - return a_nDefault; - } - - char * pszSuffix = NULL; - double nValue = strtod(szValue, &pszSuffix); - - // any invalid strings will return the default value - if (!pszSuffix || *pszSuffix) { - return a_nDefault; - } - - return nValue; + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_nDefault; + // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII + char szValue[64] = { 0 }; + SI_CONVERTER c(m_bStoreIsUtf8); + if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) + { + return a_nDefault; + } + char * pszSuffix = NULL; + double nValue = strtod(szValue, &pszSuffix); + // any invalid strings will return the default value + if (!pszSuffix || *pszSuffix) + { + return a_nDefault; + } + return nValue; } template SI_Error CSimpleIniTempl::SetDoubleValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - double a_nValue, - const SI_CHAR * a_pComment, - bool a_bForceReplace - ) + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + double a_nValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace +) { - // use SetValue to create sections - if (!a_pSection || !a_pKey) return SI_FAIL; - - // convert to an ASCII string - char szInput[64]; + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + // convert to an ASCII string + char szInput[64]; #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE - sprintf_s(szInput, "%f", a_nValue); + sprintf_s(szInput, "%f", a_nValue); #else // !__STDC_WANT_SECURE_LIB__ - sprintf(szInput, "%f", a_nValue); + sprintf(szInput, "%f", a_nValue); #endif // __STDC_WANT_SECURE_LIB__ - - // convert to output text - SI_CHAR szOutput[64]; - SI_CONVERTER c(m_bStoreIsUtf8); - c.ConvertFromStore(szInput, strlen(szInput) + 1, - szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); - - // actually add it - return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(szInput, strlen(szInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); } template bool CSimpleIniTempl::GetBoolValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - bool a_bDefault, - bool * a_pHasMultiple - ) const + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bDefault, + bool * a_pHasMultiple +) const { - // return the default if we don't have a value - const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); - if (!pszValue || !*pszValue) return a_bDefault; - - // we only look at the minimum number of characters - switch (pszValue[0]) { - case 't': case 'T': // true - case 'y': case 'Y': // yes - case '1': // 1 (one) - return true; - - case 'f': case 'F': // false - case 'n': case 'N': // no - case '0': // 0 (zero) - return false; - - case 'o': case 'O': - if (pszValue[1] == 'n' || pszValue[1] == 'N') return true; // on - if (pszValue[1] == 'f' || pszValue[1] == 'F') return false; // off - break; - } - - // no recognized value, return the default - return a_bDefault; + // return the default if we don't have a value + const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple); + if (!pszValue || !*pszValue) return a_bDefault; + // we only look at the minimum number of characters + switch (pszValue[0]) + { + case 't': + case 'T': // true + case 'y': + case 'Y': // yes + case '1': // 1 (one) + return true; + case 'f': + case 'F': // false + case 'n': + case 'N': // no + case '0': // 0 (zero) + return false; + case 'o': + case 'O': + if (pszValue[1] == 'n' || pszValue[1] == 'N') return true; // on + if (pszValue[1] == 'f' || pszValue[1] == 'F') return false; // off + break; + } + // no recognized value, return the default + return a_bDefault; } template SI_Error CSimpleIniTempl::SetBoolValue( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - bool a_bValue, - const SI_CHAR * a_pComment, - bool a_bForceReplace - ) + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bValue, + const SI_CHAR * a_pComment, + bool a_bForceReplace +) { - // use SetValue to create sections - if (!a_pSection || !a_pKey) return SI_FAIL; - - // convert to an ASCII string - const char * pszInput = a_bValue ? "true" : "false"; - - // convert to output text - SI_CHAR szOutput[64]; - SI_CONVERTER c(m_bStoreIsUtf8); - c.ConvertFromStore(pszInput, strlen(pszInput) + 1, - szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); - - // actually add it - return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); + // use SetValue to create sections + if (!a_pSection || !a_pKey) return SI_FAIL; + // convert to an ASCII string + const char * pszInput = a_bValue ? "true" : "false"; + // convert to output text + SI_CHAR szOutput[64]; + SI_CONVERTER c(m_bStoreIsUtf8); + c.ConvertFromStore(pszInput, strlen(pszInput) + 1, + szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); + // actually add it + return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); } template bool CSimpleIniTempl::GetAllValues( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - TNamesDepend & a_values - ) const + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + TNamesDepend & a_values +) const { - a_values.clear(); - - if (!a_pSection || !a_pKey) { - return false; + a_values.clear(); + if (!a_pSection || !a_pKey) + { + return false; + } + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) + { + return false; + } + typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) + { + return false; + } + // insert all values for this key + a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); + if (m_bAllowMultiKey) + { + ++iKeyVal; + while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) + { + a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); + ++iKeyVal; } - typename TSection::const_iterator iSection = m_data.find(a_pSection); - if (iSection == m_data.end()) { - return false; - } - typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey); - if (iKeyVal == iSection->second.end()) { - return false; - } - - // insert all values for this key - a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); - if (m_bAllowMultiKey) { - ++iKeyVal; - while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) { - a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder)); - ++iKeyVal; - } - } - - return true; + } + return true; } template int CSimpleIniTempl::GetSectionSize( - const SI_CHAR * a_pSection - ) const + const SI_CHAR * a_pSection +) const { - if (!a_pSection) { - return -1; + if (!a_pSection) + { + return -1; + } + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) + { + return -1; + } + const TKeyVal & section = iSection->second; + // if multi-key isn't permitted then the section size is + // the number of keys that we have. + if (!m_bAllowMultiKey || section.empty()) + { + return (int) section.size(); + } + // otherwise we need to count them + int nCount = 0; + const SI_CHAR * pLastKey = NULL; + typename TKeyVal::const_iterator iKeyVal = section.begin(); + for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) + { + if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) + { + ++nCount; + pLastKey = iKeyVal->first.pItem; } - - typename TSection::const_iterator iSection = m_data.find(a_pSection); - if (iSection == m_data.end()) { - return -1; - } - const TKeyVal & section = iSection->second; - - // if multi-key isn't permitted then the section size is - // the number of keys that we have. - if (!m_bAllowMultiKey || section.empty()) { - return (int) section.size(); - } - - // otherwise we need to count them - int nCount = 0; - const SI_CHAR * pLastKey = NULL; - typename TKeyVal::const_iterator iKeyVal = section.begin(); - for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) { - if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) { - ++nCount; - pLastKey = iKeyVal->first.pItem; - } - } - return nCount; + } + return nCount; } template const typename CSimpleIniTempl::TKeyVal * CSimpleIniTempl::GetSection( - const SI_CHAR * a_pSection - ) const + const SI_CHAR * a_pSection +) const { - if (a_pSection) { - typename TSection::const_iterator i = m_data.find(a_pSection); - if (i != m_data.end()) { - return &(i->second); - } + if (a_pSection) + { + typename TSection::const_iterator i = m_data.find(a_pSection); + if (i != m_data.end()) + { + return &(i->second); } - return 0; + } + return 0; } template void CSimpleIniTempl::GetAllSections( - TNamesDepend & a_names - ) const + TNamesDepend & a_names +) const { - a_names.clear(); - typename TSection::const_iterator i = m_data.begin(); - for (int n = 0; i != m_data.end(); ++i, ++n ) { - a_names.push_back(i->first); - } + a_names.clear(); + typename TSection::const_iterator i = m_data.begin(); + for (int n = 0; i != m_data.end(); ++i, ++n ) + { + a_names.push_back(i->first); + } } template bool CSimpleIniTempl::GetAllKeys( - const SI_CHAR * a_pSection, - TNamesDepend & a_names - ) const + const SI_CHAR * a_pSection, + TNamesDepend & a_names +) const { - a_names.clear(); - - if (!a_pSection) { - return false; + a_names.clear(); + if (!a_pSection) + { + return false; + } + typename TSection::const_iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) + { + return false; + } + const TKeyVal & section = iSection->second; + const SI_CHAR * pLastKey = NULL; + typename TKeyVal::const_iterator iKeyVal = section.begin(); + for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) + { + if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) + { + a_names.push_back(iKeyVal->first); + pLastKey = iKeyVal->first.pItem; } - - typename TSection::const_iterator iSection = m_data.find(a_pSection); - if (iSection == m_data.end()) { - return false; - } - - const TKeyVal & section = iSection->second; - const SI_CHAR * pLastKey = NULL; - typename TKeyVal::const_iterator iKeyVal = section.begin(); - for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) { - if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) { - a_names.push_back(iKeyVal->first); - pLastKey = iKeyVal->first.pItem; - } - } - - return true; + } + return true; } template SI_Error CSimpleIniTempl::SaveFile( - const char * a_pszFile, - bool a_bAddSignature - ) const + const char * a_pszFile, + bool a_bAddSignature +) const { - FILE * fp = NULL; + FILE * fp = NULL; #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE - fopen_s(&fp, a_pszFile, "wb"); + fopen_s(&fp, a_pszFile, "wb"); #else // !__STDC_WANT_SECURE_LIB__ - fp = fopen(a_pszFile, "wb"); + fp = fopen(a_pszFile, "wb"); #endif // __STDC_WANT_SECURE_LIB__ - if (!fp) return SI_FILE; - SI_Error rc = SaveFile(fp, a_bAddSignature); - fclose(fp); - return rc; + if (!fp) return SI_FILE; + SI_Error rc = SaveFile(fp, a_bAddSignature); + fclose(fp); + return rc; } #ifdef SI_HAS_WIDE_FILE template SI_Error CSimpleIniTempl::SaveFile( - const SI_WCHAR_T * a_pwszFile, - bool a_bAddSignature - ) const + const SI_WCHAR_T * a_pwszFile, + bool a_bAddSignature +) const { #ifdef _WIN32 - FILE * fp = NULL; + FILE * fp = NULL; #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE - _wfopen_s(&fp, a_pwszFile, L"wb"); + _wfopen_s(&fp, a_pwszFile, L"wb"); #else // !__STDC_WANT_SECURE_LIB__ - fp = _wfopen(a_pwszFile, L"wb"); + fp = _wfopen(a_pwszFile, L"wb"); #endif // __STDC_WANT_SECURE_LIB__ - if (!fp) return SI_FILE; - SI_Error rc = SaveFile(fp, a_bAddSignature); - fclose(fp); - return rc; + if (!fp) return SI_FILE; + SI_Error rc = SaveFile(fp, a_bAddSignature); + fclose(fp); + return rc; #else // !_WIN32 (therefore SI_CONVERT_ICU) - char szFile[256]; - u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); - return SaveFile(szFile, a_bAddSignature); + char szFile[256]; + u_austrncpy(szFile, a_pwszFile, sizeof(szFile)); + return SaveFile(szFile, a_bAddSignature); #endif // _WIN32 } #endif // SI_HAS_WIDE_FILE @@ -2358,249 +2431,260 @@ CSimpleIniTempl::SaveFile( template SI_Error CSimpleIniTempl::SaveFile( - FILE * a_pFile, - bool a_bAddSignature - ) const + FILE * a_pFile, + bool a_bAddSignature +) const { - FileWriter writer(a_pFile); - return Save(writer, a_bAddSignature); + FileWriter writer(a_pFile); + return Save(writer, a_bAddSignature); } template SI_Error CSimpleIniTempl::Save( - OutputWriter & a_oOutput, - bool a_bAddSignature - ) const + OutputWriter & a_oOutput, + bool a_bAddSignature +) const { - Converter convert(m_bStoreIsUtf8); - - // add the UTF-8 signature if it is desired - if (m_bStoreIsUtf8 && a_bAddSignature) { - a_oOutput.Write(SI_UTF8_SIGNATURE); - } - - // get all of the sections sorted in load order - TNamesDepend oSections; - GetAllSections(oSections); + Converter convert(m_bStoreIsUtf8); + // add the UTF-8 signature if it is desired + if (m_bStoreIsUtf8 && a_bAddSignature) + { + a_oOutput.Write(SI_UTF8_SIGNATURE); + } + // get all of the sections sorted in load order + TNamesDepend oSections; + GetAllSections(oSections); #if defined(_MSC_VER) && _MSC_VER <= 1200 - oSections.sort(); + oSections.sort(); #elif defined(__BORLANDC__) - oSections.sort(Entry::LoadOrder()); + oSections.sort(Entry::LoadOrder()); #else - oSections.sort(typename Entry::LoadOrder()); + oSections.sort(typename Entry::LoadOrder()); #endif - - // write the file comment if we have one - bool bNeedNewLine = false; - if (m_pFileComment) { - if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) { - return SI_FAIL; - } - bNeedNewLine = true; + // write the file comment if we have one + bool bNeedNewLine = false; + if (m_pFileComment) + { + if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) + { + return SI_FAIL; } - - // iterate through our sections and output the data - typename TNamesDepend::const_iterator iSection = oSections.begin(); - for ( ; iSection != oSections.end(); ++iSection ) { + bNeedNewLine = true; + } + // iterate through our sections and output the data + typename TNamesDepend::const_iterator iSection = oSections.begin(); + for ( ; iSection != oSections.end(); ++iSection ) + { + // write out the comment if there is one + if (iSection->pComment) + { + if (bNeedNewLine) + { + a_oOutput.Write(SI_NEWLINE_A); + a_oOutput.Write(SI_NEWLINE_A); + } + if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) + { + return SI_FAIL; + } + bNeedNewLine = false; + } + if (bNeedNewLine) + { + a_oOutput.Write(SI_NEWLINE_A); + a_oOutput.Write(SI_NEWLINE_A); + bNeedNewLine = false; + } + // write the section (unless there is no section name) + if (*iSection->pItem) + { + if (!convert.ConvertToStore(iSection->pItem)) + { + return SI_FAIL; + } + a_oOutput.Write("["); + a_oOutput.Write(convert.Data()); + a_oOutput.Write("]"); + a_oOutput.Write(SI_NEWLINE_A); + } + // get all of the keys sorted in load order + TNamesDepend oKeys; + GetAllKeys(iSection->pItem, oKeys); +#if defined(_MSC_VER) && _MSC_VER <= 1200 + oKeys.sort(); +#elif defined(__BORLANDC__) + oKeys.sort(Entry::LoadOrder()); +#else + oKeys.sort(typename Entry::LoadOrder()); +#endif + // write all keys and values + typename TNamesDepend::const_iterator iKey = oKeys.begin(); + for ( ; iKey != oKeys.end(); ++iKey) + { + // get all values for this key + TNamesDepend oValues; + GetAllValues(iSection->pItem, iKey->pItem, oValues); + typename TNamesDepend::const_iterator iValue = oValues.begin(); + for ( ; iValue != oValues.end(); ++iValue) + { // write out the comment if there is one - if (iSection->pComment) { - if (bNeedNewLine) { - a_oOutput.Write(SI_NEWLINE_A); - a_oOutput.Write(SI_NEWLINE_A); - } - if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) { - return SI_FAIL; - } - bNeedNewLine = false; + if (iValue->pComment) + { + a_oOutput.Write(SI_NEWLINE_A); + if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) + { + return SI_FAIL; + } } - - if (bNeedNewLine) { - a_oOutput.Write(SI_NEWLINE_A); - a_oOutput.Write(SI_NEWLINE_A); - bNeedNewLine = false; + // write the key + if (!convert.ConvertToStore(iKey->pItem)) + { + return SI_FAIL; } - - // write the section (unless there is no section name) - if (*iSection->pItem) { - if (!convert.ConvertToStore(iSection->pItem)) { - return SI_FAIL; - } - a_oOutput.Write("["); - a_oOutput.Write(convert.Data()); - a_oOutput.Write("]"); - a_oOutput.Write(SI_NEWLINE_A); + a_oOutput.Write(convert.Data()); + // write the value + if (!convert.ConvertToStore(iValue->pItem)) + { + return SI_FAIL; } - - // get all of the keys sorted in load order - TNamesDepend oKeys; - GetAllKeys(iSection->pItem, oKeys); -#if defined(_MSC_VER) && _MSC_VER <= 1200 - oKeys.sort(); -#elif defined(__BORLANDC__) - oKeys.sort(Entry::LoadOrder()); -#else - oKeys.sort(typename Entry::LoadOrder()); -#endif - - // write all keys and values - typename TNamesDepend::const_iterator iKey = oKeys.begin(); - for ( ; iKey != oKeys.end(); ++iKey) { - // get all values for this key - TNamesDepend oValues; - GetAllValues(iSection->pItem, iKey->pItem, oValues); - - typename TNamesDepend::const_iterator iValue = oValues.begin(); - for ( ; iValue != oValues.end(); ++iValue) { - // write out the comment if there is one - if (iValue->pComment) { - a_oOutput.Write(SI_NEWLINE_A); - if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) { - return SI_FAIL; - } - } - - // write the key - if (!convert.ConvertToStore(iKey->pItem)) { - return SI_FAIL; - } - a_oOutput.Write(convert.Data()); - - // write the value - if (!convert.ConvertToStore(iValue->pItem)) { - return SI_FAIL; - } - a_oOutput.Write(m_bSpaces ? " = " : "="); - if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) { - // multi-line data needs to be processed specially to ensure - // that we use the correct newline format for the current system - a_oOutput.Write("<<pItem)) { - return SI_FAIL; - } - a_oOutput.Write("END_OF_TEXT"); - } - else { - a_oOutput.Write(convert.Data()); - } - a_oOutput.Write(SI_NEWLINE_A); - } + a_oOutput.Write(m_bSpaces ? " = " : "="); + if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) + { + // multi-line data needs to be processed specially to ensure + // that we use the correct newline format for the current system + a_oOutput.Write("<<pItem)) + { + return SI_FAIL; + } + a_oOutput.Write("END_OF_TEXT"); } - - bNeedNewLine = true; + else + { + a_oOutput.Write(convert.Data()); + } + a_oOutput.Write(SI_NEWLINE_A); + } } - - return SI_OK; + bNeedNewLine = true; + } + return SI_OK; } template bool CSimpleIniTempl::OutputMultiLineText( - OutputWriter & a_oOutput, - Converter & a_oConverter, - const SI_CHAR * a_pText - ) const + OutputWriter & a_oOutput, + Converter & a_oConverter, + const SI_CHAR * a_pText +) const { - const SI_CHAR * pEndOfLine; - SI_CHAR cEndOfLineChar = *a_pText; - while (cEndOfLineChar) { - // find the end of this line - pEndOfLine = a_pText; - for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) /*loop*/ ; - cEndOfLineChar = *pEndOfLine; - - // temporarily null terminate, convert and output the line - *const_cast(pEndOfLine) = 0; - if (!a_oConverter.ConvertToStore(a_pText)) { - return false; - } - *const_cast(pEndOfLine) = cEndOfLineChar; - a_pText += (pEndOfLine - a_pText) + 1; - a_oOutput.Write(a_oConverter.Data()); - a_oOutput.Write(SI_NEWLINE_A); + const SI_CHAR * pEndOfLine; + SI_CHAR cEndOfLineChar = *a_pText; + while (cEndOfLineChar) + { + // find the end of this line + pEndOfLine = a_pText; + for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) /*loop*/ ; + cEndOfLineChar = *pEndOfLine; + // temporarily null terminate, convert and output the line + *const_cast(pEndOfLine) = 0; + if (!a_oConverter.ConvertToStore(a_pText)) + { + return false; } - return true; + *const_cast(pEndOfLine) = cEndOfLineChar; + a_pText += (pEndOfLine - a_pText) + 1; + a_oOutput.Write(a_oConverter.Data()); + a_oOutput.Write(SI_NEWLINE_A); + } + return true; } template bool CSimpleIniTempl::Delete( - const SI_CHAR * a_pSection, - const SI_CHAR * a_pKey, - bool a_bRemoveEmpty - ) + const SI_CHAR * a_pSection, + const SI_CHAR * a_pKey, + bool a_bRemoveEmpty +) { - if (!a_pSection) { - return false; + if (!a_pSection) + { + return false; + } + typename TSection::iterator iSection = m_data.find(a_pSection); + if (iSection == m_data.end()) + { + return false; + } + // remove a single key if we have a keyname + if (a_pKey) + { + typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey); + if (iKeyVal == iSection->second.end()) + { + return false; } - - typename TSection::iterator iSection = m_data.find(a_pSection); - if (iSection == m_data.end()) { - return false; + // remove any copied strings and then the key + typename TKeyVal::iterator iDelete; + do + { + iDelete = iKeyVal++; + DeleteString(iDelete->first.pItem); + DeleteString(iDelete->second); + iSection->second.erase(iDelete); } - - // remove a single key if we have a keyname - if (a_pKey) { - typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey); - if (iKeyVal == iSection->second.end()) { - return false; - } - - // remove any copied strings and then the key - typename TKeyVal::iterator iDelete; - do { - iDelete = iKeyVal++; - - DeleteString(iDelete->first.pItem); - DeleteString(iDelete->second); - iSection->second.erase(iDelete); - } - while (iKeyVal != iSection->second.end() - && !IsLess(a_pKey, iKeyVal->first.pItem)); - - // done now if the section is not empty or we are not pruning away - // the empty sections. Otherwise let it fall through into the section - // deletion code - if (!a_bRemoveEmpty || !iSection->second.empty()) { - return true; - } + while (iKeyVal != iSection->second.end() + && !IsLess(a_pKey, iKeyVal->first.pItem)); + // done now if the section is not empty or we are not pruning away + // the empty sections. Otherwise let it fall through into the section + // deletion code + if (!a_bRemoveEmpty || !iSection->second.empty()) + { + return true; } - else { - // delete all copied strings from this section. The actual - // entries will be removed when the section is removed. - typename TKeyVal::iterator iKeyVal = iSection->second.begin(); - for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) { - DeleteString(iKeyVal->first.pItem); - DeleteString(iKeyVal->second); - } + } + else + { + // delete all copied strings from this section. The actual + // entries will be removed when the section is removed. + typename TKeyVal::iterator iKeyVal = iSection->second.begin(); + for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) + { + DeleteString(iKeyVal->first.pItem); + DeleteString(iKeyVal->second); } - - // delete the section itself - DeleteString(iSection->first.pItem); - m_data.erase(iSection); - - return true; + } + // delete the section itself + DeleteString(iSection->first.pItem); + m_data.erase(iSection); + return true; } template void CSimpleIniTempl::DeleteString( - const SI_CHAR * a_pString - ) + const SI_CHAR * a_pString +) { - // strings may exist either inside the data block, or they will be - // individually allocated and stored in m_strings. We only physically - // delete those stored in m_strings. - if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) { - typename TNamesDepend::iterator i = m_strings.begin(); - for (;i != m_strings.end(); ++i) { - if (a_pString == i->pItem) { - delete[] const_cast(i->pItem); - m_strings.erase(i); - break; - } - } + // strings may exist either inside the data block, or they will be + // individually allocated and stored in m_strings. We only physically + // delete those stored in m_strings. + if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) + { + typename TNamesDepend::iterator i = m_strings.begin(); + for (; i != m_strings.end(); ++i) + { + if (a_pString == i->pItem) + { + delete[] const_cast(i->pItem); + m_strings.erase(i); + break; + } } + } } // --------------------------------------------------------------------------- @@ -2631,17 +2715,21 @@ CSimpleIniTempl::DeleteString( * SI_CHAR. */ template -struct SI_GenericCase { - bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { - long cmp; - for ( ;*pLeft && *pRight; ++pLeft, ++pRight) { - cmp = (long) *pLeft - (long) *pRight; - if (cmp != 0) { - return cmp < 0; - } - } - return *pRight != 0; +struct SI_GenericCase +{ + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const + { + long cmp; + for ( ; *pLeft && *pRight; ++pLeft, ++pRight) + { + cmp = (long) *pLeft - (long) *pRight; + if (cmp != 0) + { + return cmp < 0; + } } + return *pRight != 0; + } }; /** @@ -2651,38 +2739,48 @@ struct SI_GenericCase { * ASCII A-Z characters are used in the encoding of multi-byte characters. */ template -struct SI_GenericNoCase { - inline SI_CHAR locase(SI_CHAR ch) const { - return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a'); - } - bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { - long cmp; - for ( ;*pLeft && *pRight; ++pLeft, ++pRight) { - cmp = (long) locase(*pLeft) - (long) locase(*pRight); - if (cmp != 0) { - return cmp < 0; - } - } - return *pRight != 0; +struct SI_GenericNoCase +{ + inline SI_CHAR locase(SI_CHAR ch) const + { + return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a'); + } + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const + { + long cmp; + for ( ; *pLeft && *pRight; ++pLeft, ++pRight) + { + cmp = (long) locase(*pLeft) - (long) locase(*pRight); + if (cmp != 0) + { + return cmp < 0; + } } + return *pRight != 0; + } }; /** * Null conversion class for MBCS/UTF-8 to char (or equivalent). */ template -class SI_ConvertA { +class SI_ConvertA +{ bool m_bStoreIsUtf8; -protected: + protected: SI_ConvertA() { } -public: + public: SI_ConvertA(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { } /* copy and assignment */ - SI_ConvertA(const SI_ConvertA & rhs) { operator=(rhs); } - SI_ConvertA & operator=(const SI_ConvertA & rhs) { - m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; - return *this; + SI_ConvertA(const SI_ConvertA & rhs) + { + operator=(rhs); + } + SI_ConvertA & operator=(const SI_ConvertA & rhs) + { + m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; + return *this; } /** Calculate the number of SI_CHAR required for converting the input @@ -2699,14 +2797,13 @@ public: * @return -1 cast to size_t on a conversion error. */ size_t SizeFromStore( - const char * a_pInputData, - size_t a_uInputDataLen) + const char * a_pInputData, + size_t a_uInputDataLen) { - (void)a_pInputData; - SI_ASSERT(a_uInputDataLen != (size_t) -1); - - // ASCII/MBCS/UTF-8 needs no conversion - return a_uInputDataLen; + (void)a_pInputData; + SI_ASSERT(a_uInputDataLen != (size_t) -1); + // ASCII/MBCS/UTF-8 needs no conversion + return a_uInputDataLen; } /** Convert the input string from the storage format to SI_CHAR. @@ -2723,17 +2820,18 @@ public: * converted. */ bool ConvertFromStore( - const char * a_pInputData, - size_t a_uInputDataLen, - SI_CHAR * a_pOutputData, - size_t a_uOutputDataSize) + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) { - // ASCII/MBCS/UTF-8 needs no conversion - if (a_uInputDataLen > a_uOutputDataSize) { - return false; - } - memcpy(a_pOutputData, a_pInputData, a_uInputDataLen); - return true; + // ASCII/MBCS/UTF-8 needs no conversion + if (a_uInputDataLen > a_uOutputDataSize) + { + return false; + } + memcpy(a_pOutputData, a_pInputData, a_uInputDataLen); + return true; } /** Calculate the number of char required by the storage format of this @@ -2747,10 +2845,10 @@ public: * @return -1 cast to size_t on a conversion error. */ size_t SizeToStore( - const SI_CHAR * a_pInputData) + const SI_CHAR * a_pInputData) { - // ASCII/MBCS/UTF-8 needs no conversion - return strlen((const char *)a_pInputData) + 1; + // ASCII/MBCS/UTF-8 needs no conversion + return strlen((const char *)a_pInputData) + 1; } /** Convert the input string to the storage format of this data. @@ -2767,19 +2865,19 @@ public: * converted. */ bool ConvertToStore( - const SI_CHAR * a_pInputData, - char * a_pOutputData, - size_t a_uOutputDataSize) + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) { - // calc input string length (SI_CHAR type and size independent) - size_t uInputLen = strlen((const char *)a_pInputData) + 1; - if (uInputLen > a_uOutputDataSize) { - return false; - } - - // ascii/UTF-8 needs no conversion - memcpy(a_pOutputData, a_pInputData, uInputLen); - return true; + // calc input string length (SI_CHAR type and size independent) + size_t uInputLen = strlen((const char *)a_pInputData) + 1; + if (uInputLen > a_uOutputDataSize) + { + return false; + } + // ascii/UTF-8 needs no conversion + memcpy(a_pOutputData, a_pInputData, uInputLen); + return true; } }; @@ -2800,18 +2898,23 @@ public: * library functions. This can be used on all platforms. */ template -class SI_ConvertW { +class SI_ConvertW +{ bool m_bStoreIsUtf8; -protected: + protected: SI_ConvertW() { } -public: + public: SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { } /* copy and assignment */ - SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } - SI_ConvertW & operator=(const SI_ConvertW & rhs) { - m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; - return *this; + SI_ConvertW(const SI_ConvertW & rhs) + { + operator=(rhs); + } + SI_ConvertW & operator=(const SI_ConvertW & rhs) + { + m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8; + return *this; } /** Calculate the number of SI_CHAR required for converting the input @@ -2828,26 +2931,25 @@ public: * @return -1 cast to size_t on a conversion error. */ size_t SizeFromStore( - const char * a_pInputData, - size_t a_uInputDataLen) + const char * a_pInputData, + size_t a_uInputDataLen) { - SI_ASSERT(a_uInputDataLen != (size_t) -1); - - if (m_bStoreIsUtf8) { - // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t - // so we just return the same number of characters required as for - // the source text. - return a_uInputDataLen; - } - -#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux)) - // fall back processing for platforms that don't support a NULL dest to mbstowcs - // worst case scenario is 1:1, this will be a sufficient buffer size - (void)a_pInputData; + SI_ASSERT(a_uInputDataLen != (size_t) -1); + if (m_bStoreIsUtf8) + { + // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t + // so we just return the same number of characters required as for + // the source text. return a_uInputDataLen; + } +#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux)) + // fall back processing for platforms that don't support a NULL dest to mbstowcs + // worst case scenario is 1:1, this will be a sufficient buffer size + (void)a_pInputData; + return a_uInputDataLen; #else - // get the actual required buffer size - return mbstowcs(NULL, a_pInputData, a_uInputDataLen); + // get the actual required buffer size + return mbstowcs(NULL, a_pInputData, a_uInputDataLen); #endif } @@ -2865,40 +2967,42 @@ public: * converted. */ bool ConvertFromStore( - const char * a_pInputData, - size_t a_uInputDataLen, - SI_CHAR * a_pOutputData, - size_t a_uOutputDataSize) + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) { - if (m_bStoreIsUtf8) { - // This uses the Unicode reference implementation to do the - // conversion from UTF-8 to wchar_t. The required files are - // ConvertUTF.h and ConvertUTF.c which should be included in - // the distribution but are publically available from unicode.org - // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ - ConversionResult retval; - const UTF8 * pUtf8 = (const UTF8 *) a_pInputData; - if (sizeof(wchar_t) == sizeof(UTF32)) { - UTF32 * pUtf32 = (UTF32 *) a_pOutputData; - retval = ConvertUTF8toUTF32( - &pUtf8, pUtf8 + a_uInputDataLen, - &pUtf32, pUtf32 + a_uOutputDataSize, - lenientConversion); - } - else if (sizeof(wchar_t) == sizeof(UTF16)) { - UTF16 * pUtf16 = (UTF16 *) a_pOutputData; - retval = ConvertUTF8toUTF16( - &pUtf8, pUtf8 + a_uInputDataLen, - &pUtf16, pUtf16 + a_uOutputDataSize, - lenientConversion); - } - return retval == conversionOK; + if (m_bStoreIsUtf8) + { + // This uses the Unicode reference implementation to do the + // conversion from UTF-8 to wchar_t. The required files are + // ConvertUTF.h and ConvertUTF.c which should be included in + // the distribution but are publically available from unicode.org + // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ + ConversionResult retval; + const UTF8 * pUtf8 = (const UTF8 *) a_pInputData; + if (sizeof(wchar_t) == sizeof(UTF32)) + { + UTF32 * pUtf32 = (UTF32 *) a_pOutputData; + retval = ConvertUTF8toUTF32( + &pUtf8, pUtf8 + a_uInputDataLen, + &pUtf32, pUtf32 + a_uOutputDataSize, + lenientConversion); } - - // convert to wchar_t - size_t retval = mbstowcs(a_pOutputData, - a_pInputData, a_uOutputDataSize); - return retval != (size_t)(-1); + else if (sizeof(wchar_t) == sizeof(UTF16)) + { + UTF16 * pUtf16 = (UTF16 *) a_pOutputData; + retval = ConvertUTF8toUTF16( + &pUtf8, pUtf8 + a_uInputDataLen, + &pUtf16, pUtf16 + a_uOutputDataSize, + lenientConversion); + } + return retval == conversionOK; + } + // convert to wchar_t + size_t retval = mbstowcs(a_pOutputData, + a_pInputData, a_uOutputDataSize); + return retval != (size_t)(-1); } /** Calculate the number of char required by the storage format of this @@ -2912,23 +3016,27 @@ public: * @return -1 cast to size_t on a conversion error. */ size_t SizeToStore( - const SI_CHAR * a_pInputData) + const SI_CHAR * a_pInputData) { - if (m_bStoreIsUtf8) { - // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char - size_t uLen = 0; - while (a_pInputData[uLen]) { - ++uLen; - } - return (6 * uLen) + 1; + if (m_bStoreIsUtf8) + { + // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char + size_t uLen = 0; + while (a_pInputData[uLen]) + { + ++uLen; } - else { - size_t uLen = wcstombs(NULL, a_pInputData, 0); - if (uLen == (size_t)(-1)) { - return uLen; - } - return uLen + 1; // include NULL terminator + return (6 * uLen) + 1; + } + else + { + size_t uLen = wcstombs(NULL, a_pInputData, 0); + if (uLen == (size_t)(-1)) + { + return uLen; } + return uLen + 1; // include NULL terminator + } } /** Convert the input string to the storage format of this data. @@ -2945,47 +3053,51 @@ public: * converted. */ bool ConvertToStore( - const SI_CHAR * a_pInputData, - char * a_pOutputData, - size_t a_uOutputDataSize - ) + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize + ) { - if (m_bStoreIsUtf8) { - // calc input string length (SI_CHAR type and size independent) - size_t uInputLen = 0; - while (a_pInputData[uInputLen]) { - ++uInputLen; - } - ++uInputLen; // include the NULL char - - // This uses the Unicode reference implementation to do the - // conversion from wchar_t to UTF-8. The required files are - // ConvertUTF.h and ConvertUTF.c which should be included in - // the distribution but are publically available from unicode.org - // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ - ConversionResult retval; - UTF8 * pUtf8 = (UTF8 *) a_pOutputData; - if (sizeof(wchar_t) == sizeof(UTF32)) { - const UTF32 * pUtf32 = (const UTF32 *) a_pInputData; - retval = ConvertUTF32toUTF8( - &pUtf32, pUtf32 + uInputLen, - &pUtf8, pUtf8 + a_uOutputDataSize, - lenientConversion); - } - else if (sizeof(wchar_t) == sizeof(UTF16)) { - const UTF16 * pUtf16 = (const UTF16 *) a_pInputData; - retval = ConvertUTF16toUTF8( - &pUtf16, pUtf16 + uInputLen, - &pUtf8, pUtf8 + a_uOutputDataSize, - lenientConversion); - } - return retval == conversionOK; + if (m_bStoreIsUtf8) + { + // calc input string length (SI_CHAR type and size independent) + size_t uInputLen = 0; + while (a_pInputData[uInputLen]) + { + ++uInputLen; } - else { - size_t retval = wcstombs(a_pOutputData, - a_pInputData, a_uOutputDataSize); - return retval != (size_t) -1; + ++uInputLen; // include the NULL char + // This uses the Unicode reference implementation to do the + // conversion from wchar_t to UTF-8. The required files are + // ConvertUTF.h and ConvertUTF.c which should be included in + // the distribution but are publically available from unicode.org + // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/ + ConversionResult retval; + UTF8 * pUtf8 = (UTF8 *) a_pOutputData; + if (sizeof(wchar_t) == sizeof(UTF32)) + { + const UTF32 * pUtf32 = (const UTF32 *) a_pInputData; + retval = ConvertUTF32toUTF8( + &pUtf32, pUtf32 + uInputLen, + &pUtf8, pUtf8 + a_uOutputDataSize, + lenientConversion); } + else if (sizeof(wchar_t) == sizeof(UTF16)) + { + const UTF16 * pUtf16 = (const UTF16 *) a_pInputData; + retval = ConvertUTF16toUTF8( + &pUtf16, pUtf16 + uInputLen, + &pUtf8, pUtf8 + a_uOutputDataSize, + lenientConversion); + } + return retval == conversionOK; + } + else + { + size_t retval = wcstombs(a_pOutputData, + a_pInputData, a_uOutputDataSize); + return retval != (size_t) -1; + } } }; @@ -3006,24 +3118,33 @@ public: * Converts MBCS/UTF-8 to UChar using ICU. This can be used on all platforms. */ template -class SI_ConvertW { +class SI_ConvertW +{ const char * m_pEncoding; UConverter * m_pConverter; -protected: + protected: SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) { } -public: - SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) { - m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL; + public: + SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) + { + m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL; } /* copy and assignment */ - SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } - SI_ConvertW & operator=(const SI_ConvertW & rhs) { - m_pEncoding = rhs.m_pEncoding; - m_pConverter = NULL; - return *this; + SI_ConvertW(const SI_ConvertW & rhs) + { + operator=(rhs); + } + SI_ConvertW & operator=(const SI_ConvertW & rhs) + { + m_pEncoding = rhs.m_pEncoding; + m_pConverter = NULL; + return *this; + } + ~SI_ConvertW() + { + if (m_pConverter) ucnv_close(m_pConverter); } - ~SI_ConvertW() { if (m_pConverter) ucnv_close(m_pConverter); } /** Calculate the number of UChar required for converting the input * from the storage format. The storage format is always UTF-8 or MBCS. @@ -3039,29 +3160,28 @@ public: * @return -1 cast to size_t on a conversion error. */ size_t SizeFromStore( - const char * a_pInputData, - size_t a_uInputDataLen) + const char * a_pInputData, + size_t a_uInputDataLen) { - SI_ASSERT(a_uInputDataLen != (size_t) -1); - - UErrorCode nError; - - if (!m_pConverter) { - nError = U_ZERO_ERROR; - m_pConverter = ucnv_open(m_pEncoding, &nError); - if (U_FAILURE(nError)) { - return (size_t) -1; - } - } - + SI_ASSERT(a_uInputDataLen != (size_t) -1); + UErrorCode nError; + if (!m_pConverter) + { nError = U_ZERO_ERROR; - int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0, - a_pInputData, (int32_t) a_uInputDataLen, &nError); - if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) { - return (size_t) -1; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) + { + return (size_t) -1; } - - return (size_t) nLen; + } + nError = U_ZERO_ERROR; + int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0, + a_pInputData, (int32_t) a_uInputDataLen, &nError); + if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) + { + return (size_t) -1; + } + return (size_t) nLen; } /** Convert the input string from the storage format to UChar. @@ -3078,30 +3198,30 @@ public: * converted. */ bool ConvertFromStore( - const char * a_pInputData, - size_t a_uInputDataLen, - UChar * a_pOutputData, - size_t a_uOutputDataSize) + const char * a_pInputData, + size_t a_uInputDataLen, + UChar * a_pOutputData, + size_t a_uOutputDataSize) { - UErrorCode nError; - - if (!m_pConverter) { - nError = U_ZERO_ERROR; - m_pConverter = ucnv_open(m_pEncoding, &nError); - if (U_FAILURE(nError)) { - return false; - } - } - + UErrorCode nError; + if (!m_pConverter) + { nError = U_ZERO_ERROR; - ucnv_toUChars(m_pConverter, - a_pOutputData, (int32_t) a_uOutputDataSize, - a_pInputData, (int32_t) a_uInputDataLen, &nError); - if (U_FAILURE(nError)) { - return false; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) + { + return false; } - - return true; + } + nError = U_ZERO_ERROR; + ucnv_toUChars(m_pConverter, + a_pOutputData, (int32_t) a_uOutputDataSize, + a_pInputData, (int32_t) a_uInputDataLen, &nError); + if (U_FAILURE(nError)) + { + return false; + } + return true; } /** Calculate the number of char required by the storage format of this @@ -3115,26 +3235,26 @@ public: * @return -1 cast to size_t on a conversion error. */ size_t SizeToStore( - const UChar * a_pInputData) + const UChar * a_pInputData) { - UErrorCode nError; - - if (!m_pConverter) { - nError = U_ZERO_ERROR; - m_pConverter = ucnv_open(m_pEncoding, &nError); - if (U_FAILURE(nError)) { - return (size_t) -1; - } - } - + UErrorCode nError; + if (!m_pConverter) + { nError = U_ZERO_ERROR; - int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0, - a_pInputData, -1, &nError); - if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) { - return (size_t) -1; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) + { + return (size_t) -1; } - - return (size_t) nLen + 1; + } + nError = U_ZERO_ERROR; + int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0, + a_pInputData, -1, &nError); + if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) + { + return (size_t) -1; + } + return (size_t) nLen + 1; } /** Convert the input string to the storage format of this data. @@ -3151,29 +3271,29 @@ public: * converted. */ bool ConvertToStore( - const UChar * a_pInputData, - char * a_pOutputData, - size_t a_uOutputDataSize) + const UChar * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) { - UErrorCode nError; - - if (!m_pConverter) { - nError = U_ZERO_ERROR; - m_pConverter = ucnv_open(m_pEncoding, &nError); - if (U_FAILURE(nError)) { - return false; - } - } - + UErrorCode nError; + if (!m_pConverter) + { nError = U_ZERO_ERROR; - ucnv_fromUChars(m_pConverter, - a_pOutputData, (int32_t) a_uOutputDataSize, - a_pInputData, -1, &nError); - if (U_FAILURE(nError)) { - return false; + m_pConverter = ucnv_open(m_pEncoding, &nError); + if (U_FAILURE(nError)) + { + return false; } - - return true; + } + nError = U_ZERO_ERROR; + ucnv_fromUChars(m_pConverter, + a_pOutputData, (int32_t) a_uOutputDataSize, + a_pInputData, -1, &nError); + if (U_FAILURE(nError)) + { + return false; + } + return true; } }; @@ -3208,18 +3328,22 @@ public: */ #include template -struct SI_NoCase { - bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const { - if (sizeof(SI_CHAR) == sizeof(char)) { - return _mbsicmp((const unsigned char *)pLeft, - (const unsigned char *)pRight) < 0; - } - if (sizeof(SI_CHAR) == sizeof(wchar_t)) { - return _wcsicmp((const wchar_t *)pLeft, - (const wchar_t *)pRight) < 0; - } - return SI_GenericNoCase()(pLeft, pRight); +struct SI_NoCase +{ + bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const + { + if (sizeof(SI_CHAR) == sizeof(char)) + { + return _mbsicmp((const unsigned char *)pLeft, + (const unsigned char *)pRight) < 0; } + if (sizeof(SI_CHAR) == sizeof(wchar_t)) + { + return _wcsicmp((const wchar_t *)pLeft, + (const wchar_t *)pRight) < 0; + } + return SI_GenericNoCase()(pLeft, pRight); + } }; #endif // SI_NO_MBCS @@ -3230,20 +3354,26 @@ struct SI_NoCase { * Layer for Unicode in your application. */ template -class SI_ConvertW { +class SI_ConvertW +{ UINT m_uCodePage; -protected: + protected: SI_ConvertW() { } -public: - SI_ConvertW(bool a_bStoreIsUtf8) { - m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP; + public: + SI_ConvertW(bool a_bStoreIsUtf8) + { + m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP; } /* copy and assignment */ - SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); } - SI_ConvertW & operator=(const SI_ConvertW & rhs) { - m_uCodePage = rhs.m_uCodePage; - return *this; + SI_ConvertW(const SI_ConvertW & rhs) + { + operator=(rhs); + } + SI_ConvertW & operator=(const SI_ConvertW & rhs) + { + m_uCodePage = rhs.m_uCodePage; + return *this; } /** Calculate the number of SI_CHAR required for converting the input @@ -3260,16 +3390,15 @@ public: * @return -1 cast to size_t on a conversion error. */ size_t SizeFromStore( - const char * a_pInputData, - size_t a_uInputDataLen) + const char * a_pInputData, + size_t a_uInputDataLen) { - SI_ASSERT(a_uInputDataLen != (size_t) -1); - - int retval = MultiByteToWideChar( - m_uCodePage, 0, - a_pInputData, (int) a_uInputDataLen, - 0, 0); - return (size_t)(retval > 0 ? retval : -1); + SI_ASSERT(a_uInputDataLen != (size_t) -1); + int retval = MultiByteToWideChar( + m_uCodePage, 0, + a_pInputData, (int) a_uInputDataLen, + 0, 0); + return (size_t)(retval > 0 ? retval : -1); } /** Convert the input string from the storage format to SI_CHAR. @@ -3286,16 +3415,16 @@ public: * converted. */ bool ConvertFromStore( - const char * a_pInputData, - size_t a_uInputDataLen, - SI_CHAR * a_pOutputData, - size_t a_uOutputDataSize) + const char * a_pInputData, + size_t a_uInputDataLen, + SI_CHAR * a_pOutputData, + size_t a_uOutputDataSize) { - int nSize = MultiByteToWideChar( - m_uCodePage, 0, - a_pInputData, (int) a_uInputDataLen, - (wchar_t *) a_pOutputData, (int) a_uOutputDataSize); - return (nSize > 0); + int nSize = MultiByteToWideChar( + m_uCodePage, 0, + a_pInputData, (int) a_uInputDataLen, + (wchar_t *) a_pOutputData, (int) a_uOutputDataSize); + return (nSize > 0); } /** Calculate the number of char required by the storage format of this @@ -3309,13 +3438,13 @@ public: * @return -1 cast to size_t on a conversion error. */ size_t SizeToStore( - const SI_CHAR * a_pInputData) + const SI_CHAR * a_pInputData) { - int retval = WideCharToMultiByte( - m_uCodePage, 0, - (const wchar_t *) a_pInputData, -1, - 0, 0, 0, 0); - return (size_t) (retval > 0 ? retval : -1); + int retval = WideCharToMultiByte( + m_uCodePage, 0, + (const wchar_t *) a_pInputData, -1, + 0, 0, 0, 0); + return (size_t) (retval > 0 ? retval : -1); } /** Convert the input string to the storage format of this data. @@ -3332,15 +3461,15 @@ public: * converted. */ bool ConvertToStore( - const SI_CHAR * a_pInputData, - char * a_pOutputData, - size_t a_uOutputDataSize) + const SI_CHAR * a_pInputData, + char * a_pOutputData, + size_t a_uOutputDataSize) { - int retval = WideCharToMultiByte( - m_uCodePage, 0, - (const wchar_t *) a_pInputData, -1, - a_pOutputData, (int) a_uOutputDataSize, 0, 0); - return retval > 0; + int retval = WideCharToMultiByte( + m_uCodePage, 0, + (const wchar_t *) a_pInputData, -1, + a_pOutputData, (int) a_uOutputDataSize, 0, 0); + return retval > 0; } }; @@ -3352,20 +3481,20 @@ public: // --------------------------------------------------------------------------- typedef CSimpleIniTempl,SI_ConvertA > CSimpleIniA; + SI_NoCase,SI_ConvertA > CSimpleIniA; typedef CSimpleIniTempl,SI_ConvertA > CSimpleIniCaseA; + SI_Case,SI_ConvertA > CSimpleIniCaseA; #if defined(SI_CONVERT_ICU) typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniW; + SI_NoCase,SI_ConvertW > CSimpleIniW; typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniCaseW; + SI_Case,SI_ConvertW > CSimpleIniCaseW; #else typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniW; + SI_NoCase,SI_ConvertW > CSimpleIniW; typedef CSimpleIniTempl,SI_ConvertW > CSimpleIniCaseW; + SI_Case,SI_ConvertW > CSimpleIniCaseW; #endif #ifdef _UNICODE diff --git a/src/openalpr/simpleini/snippets.cpp b/src/openalpr/simpleini/snippets.cpp index e2295fe..e1425cd 100644 --- a/src/openalpr/simpleini/snippets.cpp +++ b/src/openalpr/simpleini/snippets.cpp @@ -19,105 +19,106 @@ bool snippets( - const char * a_pszFile, - bool a_bIsUtf8, - bool a_bUseMultiKey, - bool a_bUseMultiLine - ) + const char * a_pszFile, + bool a_bIsUtf8, + bool a_bUseMultiKey, + bool a_bUseMultiLine +) { - // LOADING DATA + // LOADING DATA - // load from a data file - CSimpleIniA ini(a_bIsUtf8, a_bUseMultiKey, a_bUseMultiLine); - SI_Error rc = ini.LoadFile(a_pszFile); - if (rc < 0) return false; + // load from a data file + CSimpleIniA ini(a_bIsUtf8, a_bUseMultiKey, a_bUseMultiLine); + SI_Error rc = ini.LoadFile(a_pszFile); + if (rc < 0) return false; - // load from a string - std::string strData; - rc = ini.LoadData(strData.c_str(), strData.size()); - if (rc < 0) return false; + // load from a string + std::string strData; + rc = ini.LoadData(strData.c_str(), strData.size()); + if (rc < 0) return false; - // GETTING SECTIONS AND KEYS + // GETTING SECTIONS AND KEYS - // get all sections - CSimpleIniA::TNamesDepend sections; - ini.GetAllSections(sections); + // get all sections + CSimpleIniA::TNamesDepend sections; + ini.GetAllSections(sections); - // get all keys in a section - CSimpleIniA::TNamesDepend keys; - ini.GetAllKeys("section-name", keys); + // get all keys in a section + CSimpleIniA::TNamesDepend keys; + ini.GetAllKeys("section-name", keys); - // GETTING VALUES + // GETTING VALUES - // get the value of a key - const char * pszValue = ini.GetValue("section-name", - "key-name", NULL /*default*/); + // get the value of a key + const char * pszValue = ini.GetValue("section-name", + "key-name", NULL /*default*/); - // get the value of a key which may have multiple - // values. If bHasMultipleValues is true, then just - // one value has been returned - bool bHasMultipleValues; - pszValue = ini.GetValue("section-name", "key-name", - NULL /*default*/, &bHasMultipleValues); + // get the value of a key which may have multiple + // values. If bHasMultipleValues is true, then just + // one value has been returned + bool bHasMultipleValues; + pszValue = ini.GetValue("section-name", "key-name", + NULL /*default*/, &bHasMultipleValues); - // get all values of a key with multiple values - CSimpleIniA::TNamesDepend values; - ini.GetAllValues("section-name", "key-name", values); + // get all values of a key with multiple values + CSimpleIniA::TNamesDepend values; + ini.GetAllValues("section-name", "key-name", values); - // sort the values into the original load order + // sort the values into the original load order #if defined(_MSC_VER) && _MSC_VER <= 1200 - /** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */ - values.sort(); + /** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */ + values.sort(); #else - values.sort(CSimpleIniA::Entry::LoadOrder()); + values.sort(CSimpleIniA::Entry::LoadOrder()); #endif - // output all of the items - CSimpleIniA::TNamesDepend::const_iterator i; - for (i = values.begin(); i != values.end(); ++i) { - printf("key-name = '%s'\n", i->pItem); - } + // output all of the items + CSimpleIniA::TNamesDepend::const_iterator i; + for (i = values.begin(); i != values.end(); ++i) + { + printf("key-name = '%s'\n", i->pItem); + } - // MODIFYING DATA + // MODIFYING DATA - // adding a new section - rc = ini.SetValue("new-section", NULL, NULL); - if (rc < 0) return false; - printf("section: %s\n", rc == SI_INSERTED ? - "inserted" : "updated"); + // adding a new section + rc = ini.SetValue("new-section", NULL, NULL); + if (rc < 0) return false; + printf("section: %s\n", rc == SI_INSERTED ? + "inserted" : "updated"); - // adding a new key ("new-section" will be added - // automatically if it doesn't already exist. - rc = ini.SetValue("new-section", "new-key", "value"); - if (rc < 0) return false; - printf("key: %s\n", rc == SI_INSERTED ? - "inserted" : "updated"); + // adding a new key ("new-section" will be added + // automatically if it doesn't already exist. + rc = ini.SetValue("new-section", "new-key", "value"); + if (rc < 0) return false; + printf("key: %s\n", rc == SI_INSERTED ? + "inserted" : "updated"); - // changing the value of a key - rc = ini.SetValue("section", "key", "updated-value"); - if (rc < 0) return false; - printf("key: %s\n", rc == SI_INSERTED ? - "inserted" : "updated"); + // changing the value of a key + rc = ini.SetValue("section", "key", "updated-value"); + if (rc < 0) return false; + printf("key: %s\n", rc == SI_INSERTED ? + "inserted" : "updated"); - // DELETING DATA + // DELETING DATA - // deleting a key from a section. Optionally the entire - // section may be deleted if it is now empty. - ini.Delete("section-name", "key-name", - true /*delete the section if empty*/); + // deleting a key from a section. Optionally the entire + // section may be deleted if it is now empty. + ini.Delete("section-name", "key-name", + true /*delete the section if empty*/); - // deleting an entire section and all keys in it - ini.Delete("section-name", NULL); + // deleting an entire section and all keys in it + ini.Delete("section-name", NULL); - // SAVING DATA + // SAVING DATA - // save the data to a string - rc = ini.Save(strData); - if (rc < 0) return false; + // save the data to a string + rc = ini.Save(strData); + if (rc < 0) return false; - // save the data back to the file - rc = ini.SaveFile(a_pszFile); - if (rc < 0) return false; + // save the data back to the file + rc = ini.SaveFile(a_pszFile); + if (rc < 0) return false; - return true; + return true; } diff --git a/src/openalpr/stateidentifier.cpp b/src/openalpr/stateidentifier.cpp index 82e15c6..c32a536 100644 --- a/src/openalpr/stateidentifier.cpp +++ b/src/openalpr/stateidentifier.cpp @@ -19,20 +19,19 @@ #include "stateidentifier.h" - StateIdentifier::StateIdentifier(Config* config) { this->config = config; - featureMatcher = new FeatureMatcher(config); + featureMatcher = new FeatureMatcher(config); - if (featureMatcher->isLoaded() == false) - { - cout << "Can not create detector or descriptor extractor or descriptor matcher of given types" << endl; - return; - } + if (featureMatcher->isLoaded() == false) + { + cout << "Can not create detector or descriptor extractor or descriptor matcher of given types" << endl; + return; + } - featureMatcher->loadRecognitionSet(config->country); + featureMatcher->loadRecognitionSet(config->country); } StateIdentifier::~StateIdentifier() @@ -66,19 +65,16 @@ int StateIdentifier::recognize(Mat img, char* stateCode) plateImg.copyTo(debugImg); vector matchesArray(featureMatcher->numTrainingElements()); - RecognitionResult result = featureMatcher->recognize(plateImg, true, &debugImg, true, matchesArray ); if (this->config->debugStateId) { - displayImage(config, "State Identifier1", plateImg); displayImage(config, "State Identifier", debugImg); cout << result.haswinner << " : " << result.confidence << " : " << result.winner << endl; } - if (config->debugTiming) { timespec endTime; @@ -86,12 +82,10 @@ int StateIdentifier::recognize(Mat img, char* stateCode) cout << "State Identification Time: " << diffclock(startTime, endTime) << "ms." << endl; } - if (result.haswinner == false) return 0; strcpy(stateCode, result.winner.c_str()); - return result.confidence; } diff --git a/src/openalpr/support/filesystem.cpp b/src/openalpr/support/filesystem.cpp index e3cd1ee..4757d5f 100644 --- a/src/openalpr/support/filesystem.cpp +++ b/src/openalpr/support/filesystem.cpp @@ -1,43 +1,44 @@ #include "filesystem.h" - - bool hasEnding (std::string const &fullString, std::string const &ending) { - if (fullString.length() >= ending.length()) { - return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); - } else { - return false; - } + if (fullString.length() >= ending.length()) + { + return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); + } + else + { + return false; + } } bool DirectoryExists( const char* pzPath ) { - if ( pzPath == NULL) return false; + if ( pzPath == NULL) return false; - DIR *pDir; - bool bExists = false; + DIR *pDir; + bool bExists = false; - pDir = opendir (pzPath); + pDir = opendir (pzPath); - if (pDir != NULL) - { - bExists = true; - (void) closedir (pDir); - } + if (pDir != NULL) + { + bExists = true; + (void) closedir (pDir); + } - return bExists; + return bExists; } bool fileExists( const char* pzPath ) { - if (pzPath == NULL) return false; + if (pzPath == NULL) return false; - bool fExists = false; - std::ifstream f(pzPath); - fExists = f.is_open(); - f.close(); - return fExists; + bool fExists = false; + std::ifstream f(pzPath); + fExists = f.is_open(); + f.close(); + return fExists; } std::vector getFilesInDir(const char* dirPath) @@ -47,14 +48,18 @@ std::vector getFilesInDir(const char* dirPath) std::vector files; struct dirent *ent; - if ((dir = opendir (dirPath)) != NULL) { + if ((dir = opendir (dirPath)) != NULL) + { /* print all the files and directories within directory */ - while ((ent = readdir (dir)) != NULL) { + while ((ent = readdir (dir)) != NULL) + { if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) - files.push_back(ent->d_name); + files.push_back(ent->d_name); } closedir (dir); - } else { + } + else + { /* could not open directory */ perror (""); return files; @@ -63,14 +68,14 @@ std::vector getFilesInDir(const char* dirPath) return files; } - -bool stringCompare( const std::string &left, const std::string &right ){ - for( std::string::const_iterator lit = left.begin(), rit = right.begin(); lit != left.end() && rit != right.end(); ++lit, ++rit ) - if( tolower( *lit ) < tolower( *rit ) ) - return true; - else if( tolower( *lit ) > tolower( *rit ) ) - return false; - if( left.size() < right.size() ) +bool stringCompare( const std::string &left, const std::string &right ) +{ + for( std::string::const_iterator lit = left.begin(), rit = right.begin(); lit != left.end() && rit != right.end(); ++lit, ++rit ) + if( tolower( *lit ) < tolower( *rit ) ) return true; - return false; + else if( tolower( *lit ) > tolower( *rit ) ) + return false; + if( left.size() < right.size() ) + return true; + return false; } diff --git a/src/openalpr/support/filesystem.h b/src/openalpr/support/filesystem.h index 61e052c..9bff48f 100644 --- a/src/openalpr/support/filesystem.h +++ b/src/openalpr/support/filesystem.h @@ -4,12 +4,12 @@ #ifdef WINDOWS - #include "windows/dirent.h" - #include "windows/utils.h" - #include "windows/unistd_partial.h" +#include "windows/dirent.h" +#include "windows/utils.h" +#include "windows/unistd_partial.h" #else - #include - #include +#include +#include #endif #include @@ -19,12 +19,12 @@ #include - bool hasEnding (std::string const &fullString, std::string const &ending); - bool DirectoryExists( const char* pzPath ); - bool fileExists( const char* pzPath ); - std::vector getFilesInDir(const char* dirPath); +bool hasEnding (std::string const &fullString, std::string const &ending); +bool DirectoryExists( const char* pzPath ); +bool fileExists( const char* pzPath ); +std::vector getFilesInDir(const char* dirPath); - bool stringCompare( const std::string &left, const std::string &right ); +bool stringCompare( const std::string &left, const std::string &right ); #endif // FILESYSTEM_H diff --git a/src/openalpr/support/timing.cpp b/src/openalpr/support/timing.cpp index 066af2a..dbf1c7a 100644 --- a/src/openalpr/support/timing.cpp +++ b/src/openalpr/support/timing.cpp @@ -1,143 +1,144 @@ #include "timing.h" - timespec diff(timespec start, timespec end); - #ifdef WINDOWS // Windows timing code LARGE_INTEGER getFILETIMEoffset() { - SYSTEMTIME s; - FILETIME f; - LARGE_INTEGER t; + SYSTEMTIME s; + FILETIME f; + LARGE_INTEGER t; - s.wYear = 1970; - s.wMonth = 1; - s.wDay = 1; - s.wHour = 0; - s.wMinute = 0; - s.wSecond = 0; - s.wMilliseconds = 0; - SystemTimeToFileTime(&s, &f); - t.QuadPart = f.dwHighDateTime; - t.QuadPart <<= 32; - t.QuadPart |= f.dwLowDateTime; - return (t); + s.wYear = 1970; + s.wMonth = 1; + s.wDay = 1; + s.wHour = 0; + s.wMinute = 0; + s.wSecond = 0; + s.wMilliseconds = 0; + SystemTimeToFileTime(&s, &f); + t.QuadPart = f.dwHighDateTime; + t.QuadPart <<= 32; + t.QuadPart |= f.dwLowDateTime; + return (t); } int clock_gettime(int X, timespec *tv) { - LARGE_INTEGER t; - FILETIME f; - double microseconds; - static LARGE_INTEGER offset; - static double frequencyToMicroseconds; - static int initialized = 0; - static BOOL usePerformanceCounter = 0; + LARGE_INTEGER t; + FILETIME f; + double microseconds; + static LARGE_INTEGER offset; + static double frequencyToMicroseconds; + static int initialized = 0; + static BOOL usePerformanceCounter = 0; - if (!initialized) { - LARGE_INTEGER performanceFrequency; - initialized = 1; - usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency); - if (usePerformanceCounter) { - QueryPerformanceCounter(&offset); - frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.; - } else { - offset = getFILETIMEoffset(); - frequencyToMicroseconds = 10.; - } + if (!initialized) + { + LARGE_INTEGER performanceFrequency; + initialized = 1; + usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency); + if (usePerformanceCounter) + { + QueryPerformanceCounter(&offset); + frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.; } - if (usePerformanceCounter) QueryPerformanceCounter(&t); - else { - GetSystemTimeAsFileTime(&f); - t.QuadPart = f.dwHighDateTime; - t.QuadPart <<= 32; - t.QuadPart |= f.dwLowDateTime; + else + { + offset = getFILETIMEoffset(); + frequencyToMicroseconds = 10.; } + } + if (usePerformanceCounter) QueryPerformanceCounter(&t); + else + { + GetSystemTimeAsFileTime(&f); + t.QuadPart = f.dwHighDateTime; + t.QuadPart <<= 32; + t.QuadPart |= f.dwLowDateTime; + } - t.QuadPart -= offset.QuadPart; - microseconds = (double)t.QuadPart / frequencyToMicroseconds; - t.QuadPart = microseconds; - tv->tv_sec = t.QuadPart / 1000000; - tv->tv_usec = t.QuadPart % 1000000; - return (0); + t.QuadPart -= offset.QuadPart; + microseconds = (double)t.QuadPart / frequencyToMicroseconds; + t.QuadPart = microseconds; + tv->tv_sec = t.QuadPart / 1000000; + tv->tv_usec = t.QuadPart % 1000000; + return (0); } - - void getTime(timespec* time) { - clock_gettime(0, time); + clock_gettime(0, time); } double diffclock(timespec time1,timespec time2) { - timespec delta = diff(time1,time2); - double milliseconds = (delta.tv_sec * 1000) + (((double) delta.tv_usec) / 1000.0); + timespec delta = diff(time1,time2); + double milliseconds = (delta.tv_sec * 1000) + (((double) delta.tv_usec) / 1000.0); - - return milliseconds; + return milliseconds; } timespec diff(timespec start, timespec end) { - timespec temp; - if ((end.tv_usec-start.tv_usec)<0) { - temp.tv_sec = end.tv_sec-start.tv_sec-1; - temp.tv_usec = 1000000+end.tv_usec-start.tv_usec; - } else { - temp.tv_sec = end.tv_sec-start.tv_sec; - temp.tv_usec = end.tv_usec-start.tv_usec; - } - return temp; + timespec temp; + if ((end.tv_usec-start.tv_usec)<0) + { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_usec = 1000000+end.tv_usec-start.tv_usec; + } + else + { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_usec = end.tv_usec-start.tv_usec; + } + return temp; } #else - - void getTime(timespec* time) { #ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time - clock_serv_t cclock; - mach_timespec_t mts; - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self(), cclock); - time->tv_sec = mts.tv_sec; - time->tv_nsec = mts.tv_nsec; + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + time->tv_sec = mts.tv_sec; + time->tv_nsec = mts.tv_nsec; #else - clock_gettime(CLOCK_PROCESS_CPUTIME_ID, time); + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, time); #endif } double diffclock(timespec time1,timespec time2) { - timespec delta = diff(time1,time2); - double milliseconds = (delta.tv_sec * 1000) + (((double) delta.tv_nsec) / 1000000.0); - - - return milliseconds; + timespec delta = diff(time1,time2); + double milliseconds = (delta.tv_sec * 1000) + (((double) delta.tv_nsec) / 1000000.0); + return milliseconds; } timespec diff(timespec start, timespec end) { - timespec temp; - if ((end.tv_nsec-start.tv_nsec)<0) { - temp.tv_sec = end.tv_sec-start.tv_sec-1; - temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; - } else { - temp.tv_sec = end.tv_sec-start.tv_sec; - temp.tv_nsec = end.tv_nsec-start.tv_nsec; - } - return temp; + timespec temp; + if ((end.tv_nsec-start.tv_nsec)<0) + { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; + } + else + { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_nsec = end.tv_nsec-start.tv_nsec; + } + return temp; } - #endif diff --git a/src/openalpr/support/timing.h b/src/openalpr/support/timing.h index 608877d..843629e 100644 --- a/src/openalpr/support/timing.h +++ b/src/openalpr/support/timing.h @@ -11,13 +11,13 @@ // Support for Windows #ifdef WINDOWS - #include +#include - #define timespec timeval +#define timespec timeval #endif - void getTime(timespec* time); - double diffclock(timespec time1,timespec time2); +void getTime(timespec* time); +double diffclock(timespec time1,timespec time2); #endif diff --git a/src/openalpr/support/tinydir.h b/src/openalpr/support/tinydir.h index 694f5cd..1f0d26c 100644 --- a/src/openalpr/support/tinydir.h +++ b/src/openalpr/support/tinydir.h @@ -61,30 +61,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. typedef struct { - char path[_TINYDIR_PATH_MAX]; - char name[_TINYDIR_FILENAME_MAX]; - int is_dir; - int is_reg; + char path[_TINYDIR_PATH_MAX]; + char name[_TINYDIR_FILENAME_MAX]; + int is_dir; + int is_reg; #ifdef _MSC_VER #else - struct stat _s; + struct stat _s; #endif } tinydir_file; typedef struct { - char path[_TINYDIR_PATH_MAX]; - int has_next; - int n_files; + char path[_TINYDIR_PATH_MAX]; + int has_next; + int n_files; - tinydir_file *_files; + tinydir_file *_files; #ifdef _MSC_VER - HANDLE _h; - WIN32_FIND_DATA _f; + HANDLE _h; + WIN32_FIND_DATA _f; #else - DIR *_d; - struct dirent *_e; + DIR *_d; + struct dirent *_e; #endif } tinydir_dir; @@ -116,308 +116,288 @@ int _tinydir_file_cmp(const void *a, const void *b); _TINYDIR_FUNC int tinydir_open(tinydir_dir *dir, const char *path) { - if (dir == NULL || path == NULL || strlen(path) == 0) - { - errno = EINVAL; - return -1; - } - if (strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) - { - errno = ENAMETOOLONG; - return -1; - } - - /* initialise dir */ - dir->_files = NULL; + if (dir == NULL || path == NULL || strlen(path) == 0) + { + errno = EINVAL; + return -1; + } + if (strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) + { + errno = ENAMETOOLONG; + return -1; + } + /* initialise dir */ + dir->_files = NULL; #ifdef _MSC_VER - dir->_h = INVALID_HANDLE_VALUE; + dir->_h = INVALID_HANDLE_VALUE; #else - dir->_d = NULL; + dir->_d = NULL; #endif - tinydir_close(dir); - - strcpy(dir->path, path); + tinydir_close(dir); + strcpy(dir->path, path); #ifdef _MSC_VER - strcat(dir->path, "\\*"); - dir->_h = FindFirstFile(dir->path, &dir->_f); - dir->path[strlen(dir->path) - 2] = '\0'; - if (dir->_h == INVALID_HANDLE_VALUE) + strcat(dir->path, "\\*"); + dir->_h = FindFirstFile(dir->path, &dir->_f); + dir->path[strlen(dir->path) - 2] = '\0'; + if (dir->_h == INVALID_HANDLE_VALUE) #else - dir->_d = opendir(path); - if (dir->_d == NULL) + dir->_d = opendir(path); + if (dir->_d == NULL) #endif - { - errno = ENOENT; - goto bail; - } - - /* read first file */ - dir->has_next = 1; + { + errno = ENOENT; + goto bail; + } + /* read first file */ + dir->has_next = 1; #ifndef _MSC_VER - dir->_e = readdir(dir->_d); - if (dir->_e == NULL) - { - dir->has_next = 0; - } + dir->_e = readdir(dir->_d); + if (dir->_e == NULL) + { + dir->has_next = 0; + } #endif - - return 0; - + return 0; bail: - tinydir_close(dir); - return -1; + tinydir_close(dir); + return -1; } _TINYDIR_FUNC int tinydir_open_sorted(tinydir_dir *dir, const char *path) { - if (tinydir_open(dir, path) == -1) - { - return -1; - } - - dir->n_files = 0; - while (dir->has_next) - { - tinydir_file *p_file; - dir->n_files++; - dir->_files = (tinydir_file *)realloc(dir->_files, sizeof(tinydir_file)*dir->n_files); - if (dir->_files == NULL) - { - errno = ENOMEM; - goto bail; - } - - p_file = &dir->_files[dir->n_files - 1]; - if (tinydir_readfile(dir, p_file) == -1) - { - goto bail; - } - - if (tinydir_next(dir) == -1) - { - goto bail; - } - } - - qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp); - - return 0; - + if (tinydir_open(dir, path) == -1) + { + return -1; + } + dir->n_files = 0; + while (dir->has_next) + { + tinydir_file *p_file; + dir->n_files++; + dir->_files = (tinydir_file *)realloc(dir->_files, sizeof(tinydir_file)*dir->n_files); + if (dir->_files == NULL) + { + errno = ENOMEM; + goto bail; + } + p_file = &dir->_files[dir->n_files - 1]; + if (tinydir_readfile(dir, p_file) == -1) + { + goto bail; + } + if (tinydir_next(dir) == -1) + { + goto bail; + } + } + qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp); + return 0; bail: - tinydir_close(dir); - return -1; + tinydir_close(dir); + return -1; } _TINYDIR_FUNC void tinydir_close(tinydir_dir *dir) { - if (dir == NULL) - { - return; - } - - memset(dir->path, 0, sizeof(dir->path)); - dir->has_next = 0; - dir->n_files = -1; - if (dir->_files != NULL) - { - free(dir->_files); - } - dir->_files = NULL; + if (dir == NULL) + { + return; + } + memset(dir->path, 0, sizeof(dir->path)); + dir->has_next = 0; + dir->n_files = -1; + if (dir->_files != NULL) + { + free(dir->_files); + } + dir->_files = NULL; #ifdef _MSC_VER - if (dir->_h != INVALID_HANDLE_VALUE) - { - FindClose(dir->_h); - } - dir->_h = INVALID_HANDLE_VALUE; + if (dir->_h != INVALID_HANDLE_VALUE) + { + FindClose(dir->_h); + } + dir->_h = INVALID_HANDLE_VALUE; #else - if (dir->_d) - { - closedir(dir->_d); - } - dir->_d = NULL; - dir->_e = NULL; + if (dir->_d) + { + closedir(dir->_d); + } + dir->_d = NULL; + dir->_e = NULL; #endif } _TINYDIR_FUNC int tinydir_next(tinydir_dir *dir) { - if (dir == NULL) - { - errno = EINVAL; - return -1; - } - if (!dir->has_next) - { - errno = ENOENT; - return -1; - } - + if (dir == NULL) + { + errno = EINVAL; + return -1; + } + if (!dir->has_next) + { + errno = ENOENT; + return -1; + } #ifdef _MSC_VER - if (FindNextFile(dir->_h, &dir->_f) == 0) + if (FindNextFile(dir->_h, &dir->_f) == 0) #else - dir->_e = readdir(dir->_d); - if (dir->_e == NULL) + dir->_e = readdir(dir->_d); + if (dir->_e == NULL) #endif - { - dir->has_next = 0; + { + dir->has_next = 0; #ifdef _MSC_VER - if (GetLastError() != ERROR_SUCCESS && - GetLastError() != ERROR_NO_MORE_FILES) - { - tinydir_close(dir); - errno = EIO; - return -1; - } + if (GetLastError() != ERROR_SUCCESS && + GetLastError() != ERROR_NO_MORE_FILES) + { + tinydir_close(dir); + errno = EIO; + return -1; + } #endif - } - - return 0; + } + return 0; } _TINYDIR_FUNC int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file) { - if (dir == NULL || file == NULL) - { - errno = EINVAL; - return -1; - } + if (dir == NULL || file == NULL) + { + errno = EINVAL; + return -1; + } #ifdef _MSC_VER - if (dir->_h == INVALID_HANDLE_VALUE) + if (dir->_h == INVALID_HANDLE_VALUE) #else - if (dir->_e == NULL) + if (dir->_e == NULL) #endif - { - errno = ENOENT; - return -1; - } - if (strlen(dir->path) + - strlen( + { + errno = ENOENT; + return -1; + } + if (strlen(dir->path) + + strlen( #ifdef _MSC_VER - dir->_f.cFileName + dir->_f.cFileName #else - dir->_e->d_name + dir->_e->d_name #endif - ) + 1 + _TINYDIR_PATH_EXTRA >= - _TINYDIR_PATH_MAX) - { - /* the path for the file will be too long */ - errno = ENAMETOOLONG; - return -1; - } - if (strlen( + ) + 1 + _TINYDIR_PATH_EXTRA >= + _TINYDIR_PATH_MAX) + { + /* the path for the file will be too long */ + errno = ENAMETOOLONG; + return -1; + } + if (strlen( #ifdef _MSC_VER - dir->_f.cFileName + dir->_f.cFileName #else - dir->_e->d_name + dir->_e->d_name #endif - ) >= _TINYDIR_FILENAME_MAX) - { - errno = ENAMETOOLONG; - return -1; - } - - strcpy(file->path, dir->path); - strcat(file->path, "/"); - strcpy(file->name, + ) >= _TINYDIR_FILENAME_MAX) + { + errno = ENAMETOOLONG; + return -1; + } + strcpy(file->path, dir->path); + strcat(file->path, "/"); + strcpy(file->name, #ifdef _MSC_VER - dir->_f.cFileName + dir->_f.cFileName #else - dir->_e->d_name + dir->_e->d_name #endif - ); - strcat(file->path, file->name); + ); + strcat(file->path, file->name); #ifndef _MSC_VER - if (stat(file->path, &file->_s) == -1) - { - return -1; - } + if (stat(file->path, &file->_s) == -1) + { + return -1; + } #endif - file->is_dir = + file->is_dir = #ifdef _MSC_VER - !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); + !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); #else - S_ISDIR(file->_s.st_mode); + S_ISDIR(file->_s.st_mode); #endif - file->is_reg = + file->is_reg = #ifdef _MSC_VER - !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || - ( - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) && - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) && + !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || + ( + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) && #ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) && #endif #ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) && #endif - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) && - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY)); + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY)); #else - S_ISREG(file->_s.st_mode); + S_ISREG(file->_s.st_mode); #endif - - return 0; + return 0; } _TINYDIR_FUNC int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, int i) { - if (dir == NULL || file == NULL || i < 0) - { - errno = EINVAL; - return -1; - } - if (i >= dir->n_files) - { - errno = ENOENT; - return -1; - } - - memcpy(file, &dir->_files[i], sizeof(tinydir_file)); - - return 0; + if (dir == NULL || file == NULL || i < 0) + { + errno = EINVAL; + return -1; + } + if (i >= dir->n_files) + { + errno = ENOENT; + return -1; + } + memcpy(file, &dir->_files[i], sizeof(tinydir_file)); + return 0; } _TINYDIR_FUNC int tinydir_open_subdir_n(tinydir_dir *dir, int i) { - char path[_TINYDIR_PATH_MAX]; - if (dir == NULL || i < 0) - { - errno = EINVAL; - return -1; - } - if (i >= dir->n_files || !dir->_files[i].is_dir) - { - errno = ENOENT; - return -1; - } - - strcpy(path, dir->_files[i].path); - tinydir_close(dir); - if (tinydir_open_sorted(dir, path) == -1) - { - return -1; - } - - return 0; + char path[_TINYDIR_PATH_MAX]; + if (dir == NULL || i < 0) + { + errno = EINVAL; + return -1; + } + if (i >= dir->n_files || !dir->_files[i].is_dir) + { + errno = ENOENT; + return -1; + } + strcpy(path, dir->_files[i].path); + tinydir_close(dir); + if (tinydir_open_sorted(dir, path) == -1) + { + return -1; + } + return 0; } _TINYDIR_FUNC int _tinydir_file_cmp(const void *a, const void *b) { - const tinydir_file *fa = (const tinydir_file *)a; - const tinydir_file *fb = (const tinydir_file *)b; - if (fa->is_dir != fb->is_dir) - { - return -(fa->is_dir - fb->is_dir); - } - return strncasecmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX); + const tinydir_file *fa = (const tinydir_file *)a; + const tinydir_file *fb = (const tinydir_file *)b; + if (fa->is_dir != fb->is_dir) + { + return -(fa->is_dir - fb->is_dir); + } + return strncasecmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX); } #endif \ No newline at end of file diff --git a/src/openalpr/support/windows/dirent.h b/src/openalpr/support/windows/dirent.h index 718bde1..d434ec9 100644 --- a/src/openalpr/support/windows/dirent.h +++ b/src/openalpr/support/windows/dirent.h @@ -219,21 +219,23 @@ extern "C" { /* Wide-character version */ -struct _wdirent { - long d_ino; /* Always zero */ - unsigned short d_reclen; /* Structure size */ - size_t d_namlen; /* Length of name without \0 */ - int d_type; /* File type */ - wchar_t d_name[PATH_MAX + 1]; /* File name */ +struct _wdirent +{ + long d_ino; /* Always zero */ + unsigned short d_reclen; /* Structure size */ + size_t d_namlen; /* Length of name without \0 */ + int d_type; /* File type */ + wchar_t d_name[PATH_MAX + 1]; /* File name */ }; typedef struct _wdirent _wdirent; -struct _WDIR { - struct _wdirent ent; /* Current directory entry */ - WIN32_FIND_DATAW data; /* Private file data */ - int cached; /* True if data is valid */ - HANDLE handle; /* Win32 search handle */ - wchar_t *patt; /* Initial directory name */ +struct _WDIR +{ + struct _wdirent ent; /* Current directory entry */ + WIN32_FIND_DATAW data; /* Private file data */ + int cached; /* True if data is valid */ + HANDLE handle; /* Win32 search handle */ + wchar_t *patt; /* Initial directory name */ }; typedef struct _WDIR _WDIR; @@ -253,18 +255,20 @@ static void _wrewinddir (_WDIR* dirp); /* Multi-byte character versions */ -struct dirent { - long d_ino; /* Always zero */ - unsigned short d_reclen; /* Structure size */ - size_t d_namlen; /* Length of name without \0 */ - int d_type; /* File type */ - char d_name[PATH_MAX + 1]; /* File name */ +struct dirent +{ + long d_ino; /* Always zero */ + unsigned short d_reclen; /* Structure size */ + size_t d_namlen; /* Length of name without \0 */ + int d_type; /* File type */ + char d_name[PATH_MAX + 1]; /* File name */ }; typedef struct dirent dirent; -struct DIR { - struct dirent ent; - struct _WDIR *wdirp; +struct DIR +{ + struct dirent ent; + struct _WDIR *wdirp; }; typedef struct DIR DIR; @@ -279,18 +283,18 @@ static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); static int dirent_mbstowcs_s( - size_t *pReturnValue, - wchar_t *wcstr, - size_t sizeInWords, - const char *mbstr, - size_t count); + size_t *pReturnValue, + wchar_t *wcstr, + size_t sizeInWords, + const char *mbstr, + size_t count); static int dirent_wcstombs_s( - size_t *pReturnValue, - char *mbstr, - size_t sizeInBytes, - const wchar_t *wcstr, - size_t count); + size_t *pReturnValue, + char *mbstr, + size_t sizeInBytes, + const wchar_t *wcstr, + size_t count); static void dirent_set_errno (int error); @@ -301,95 +305,98 @@ static void dirent_set_errno (int error); */ static _WDIR* _wopendir( - const wchar_t *dirname) + const wchar_t *dirname) { - _WDIR *dirp = NULL; - int error; - - /* Must have directory name */ - if (dirname == NULL || dirname[0] == '\0') { - dirent_set_errno (ENOENT); - return NULL; - } - - /* Allocate new _WDIR structure */ - dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); - if (dirp != NULL) { - DWORD n; - - /* Reset _WDIR structure */ - dirp->handle = INVALID_HANDLE_VALUE; - dirp->patt = NULL; - dirp->cached = 0; - - /* Compute the length of full path plus zero terminator */ - n = GetFullPathNameW (dirname, 0, NULL, NULL); - - /* Allocate room for absolute directory name and search pattern */ - dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); - if (dirp->patt) { - - /* - * Convert relative directory name to an absolute one. This - * allows rewinddir() to function correctly even when current - * working directory is changed between opendir() and rewinddir(). - */ - n = GetFullPathNameW (dirname, n, dirp->patt, NULL); - if (n > 0) { - wchar_t *p; - - /* Append search pattern \* to the directory name */ - p = dirp->patt + n; - if (dirp->patt < p) { - switch (p[-1]) { - case '\\': - case '/': - case ':': - /* Directory ends in path separator, e.g. c:\temp\ */ - /*NOP*/; - break; - - default: - /* Directory name doesn't end in path separator */ - *p++ = '\\'; - } - } - *p++ = '*'; - *p = '\0'; - - /* Open directory stream and retrieve the first entry */ - if (dirent_first (dirp)) { - /* Directory stream opened successfully */ - error = 0; - } else { - /* Cannot retrieve first entry */ - error = 1; - dirent_set_errno (ENOENT); - } - - } else { - /* Cannot retrieve full path name */ - dirent_set_errno (ENOENT); - error = 1; - } - - } else { - /* Cannot allocate memory for search pattern */ - error = 1; + _WDIR *dirp = NULL; + int error; + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') + { + dirent_set_errno (ENOENT); + return NULL; + } + /* Allocate new _WDIR structure */ + dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); + if (dirp != NULL) + { + DWORD n; + /* Reset _WDIR structure */ + dirp->handle = INVALID_HANDLE_VALUE; + dirp->patt = NULL; + dirp->cached = 0; + /* Compute the length of full path plus zero terminator */ + n = GetFullPathNameW (dirname, 0, NULL, NULL); + /* Allocate room for absolute directory name and search pattern */ + dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); + if (dirp->patt) + { + /* + * Convert relative directory name to an absolute one. This + * allows rewinddir() to function correctly even when current + * working directory is changed between opendir() and rewinddir(). + */ + n = GetFullPathNameW (dirname, n, dirp->patt, NULL); + if (n > 0) + { + wchar_t *p; + /* Append search pattern \* to the directory name */ + p = dirp->patt + n; + if (dirp->patt < p) + { + switch (p[-1]) + { + case '\\': + case '/': + case ':': + /* Directory ends in path separator, e.g. c:\temp\ */ + /*NOP*/ + ; + break; + default: + /* Directory name doesn't end in path separator */ + *p++ = '\\'; + } } - - } else { - /* Cannot allocate _WDIR structure */ + *p++ = '*'; + *p = '\0'; + /* Open directory stream and retrieve the first entry */ + if (dirent_first (dirp)) + { + /* Directory stream opened successfully */ + error = 0; + } + else + { + /* Cannot retrieve first entry */ + error = 1; + dirent_set_errno (ENOENT); + } + } + else + { + /* Cannot retrieve full path name */ + dirent_set_errno (ENOENT); error = 1; + } } - - /* Clean up in case of error */ - if (error && dirp) { - _wclosedir (dirp); - dirp = NULL; + else + { + /* Cannot allocate memory for search pattern */ + error = 1; } - - return dirp; + } + else + { + /* Cannot allocate _WDIR structure */ + error = 1; + } + /* Clean up in case of error */ + if (error && dirp) + { + _wclosedir (dirp); + dirp = NULL; + } + return dirp; } /* @@ -400,57 +407,58 @@ _wopendir( */ static struct _wdirent* _wreaddir( - _WDIR *dirp) + _WDIR *dirp) { - WIN32_FIND_DATAW *datap; - struct _wdirent *entp; - - /* Read next directory entry */ - datap = dirent_next (dirp); - if (datap) { - size_t n; - DWORD attr; - - /* Pointer to directory entry to return */ - entp = &dirp->ent; - - /* - * Copy file name as wide-character string. If the file name is too - * long to fit in to the destination buffer, then truncate file name - * to PATH_MAX characters and zero-terminate the buffer. - */ - n = 0; - while (n < PATH_MAX && datap->cFileName[n] != 0) { - entp->d_name[n] = datap->cFileName[n]; - n++; - } - dirp->ent.d_name[n] = 0; - - /* Length of file name excluding zero terminator */ - entp->d_namlen = n; - - /* File type */ - attr = datap->dwFileAttributes; - if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { - entp->d_type = DT_CHR; - } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { - entp->d_type = DT_DIR; - } else { - entp->d_type = DT_REG; - } - - /* Reset dummy fields */ - entp->d_ino = 0; - entp->d_reclen = sizeof (struct _wdirent); - - } else { - - /* Last directory entry read */ - entp = NULL; + WIN32_FIND_DATAW *datap; + struct _wdirent *entp; + /* Read next directory entry */ + datap = dirent_next (dirp); + if (datap) + { + size_t n; + DWORD attr; + /* Pointer to directory entry to return */ + entp = &dirp->ent; + /* + * Copy file name as wide-character string. If the file name is too + * long to fit in to the destination buffer, then truncate file name + * to PATH_MAX characters and zero-terminate the buffer. + */ + n = 0; + while (n < PATH_MAX && datap->cFileName[n] != 0) + { + entp->d_name[n] = datap->cFileName[n]; + n++; } + dirp->ent.d_name[n] = 0; + /* Length of file name excluding zero terminator */ + entp->d_namlen = n; + /* File type */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) + { + entp->d_type = DT_CHR; + } + else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) + { + entp->d_type = DT_DIR; + } + else + { + entp->d_type = DT_REG; + } + /* Reset dummy fields */ + entp->d_ino = 0; + entp->d_reclen = sizeof (struct _wdirent); + } + else + { + /* Last directory entry read */ + entp = NULL; + } - return entp; + return entp; } /* @@ -460,33 +468,34 @@ _wreaddir( */ static int _wclosedir( - _WDIR *dirp) + _WDIR *dirp) { - int ok; - if (dirp) { - - /* Release search handle */ - if (dirp->handle != INVALID_HANDLE_VALUE) { - FindClose (dirp->handle); - dirp->handle = INVALID_HANDLE_VALUE; - } - - /* Release search pattern */ - if (dirp->patt) { - free (dirp->patt); - dirp->patt = NULL; - } - - /* Release directory structure */ - free (dirp); - ok = /*success*/0; - - } else { - /* Invalid directory stream */ - dirent_set_errno (EBADF); - ok = /*failure*/-1; + int ok; + if (dirp) + { + /* Release search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) + { + FindClose (dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; } - return ok; + /* Release search pattern */ + if (dirp->patt) + { + free (dirp->patt); + dirp->patt = NULL; + } + /* Release directory structure */ + free (dirp); + ok = /*success*/0; + } + else + { + /* Invalid directory stream */ + dirent_set_errno (EBADF); + ok = /*failure*/-1; + } + return ok; } /* @@ -495,79 +504,78 @@ _wclosedir( */ static void _wrewinddir( - _WDIR* dirp) + _WDIR* dirp) { - if (dirp) { - /* Release existing search handle */ - if (dirp->handle != INVALID_HANDLE_VALUE) { - FindClose (dirp->handle); - } - - /* Open new search handle */ - dirent_first (dirp); + if (dirp) + { + /* Release existing search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) + { + FindClose (dirp->handle); } + /* Open new search handle */ + dirent_first (dirp); + } } /* Get first directory entry (internal) */ static WIN32_FIND_DATAW* dirent_first( - _WDIR *dirp) + _WDIR *dirp) { - WIN32_FIND_DATAW *datap; - - /* Open directory and retrieve the first entry */ - dirp->handle = FindFirstFileW (dirp->patt, &dirp->data); - if (dirp->handle != INVALID_HANDLE_VALUE) { - - /* a directory entry is now waiting in memory */ - datap = &dirp->data; - dirp->cached = 1; - - } else { - - /* Failed to re-open directory: no directory entry in memory */ - dirp->cached = 0; - datap = NULL; - - } - return datap; + WIN32_FIND_DATAW *datap; + /* Open directory and retrieve the first entry */ + dirp->handle = FindFirstFileW (dirp->patt, &dirp->data); + if (dirp->handle != INVALID_HANDLE_VALUE) + { + /* a directory entry is now waiting in memory */ + datap = &dirp->data; + dirp->cached = 1; + } + else + { + /* Failed to re-open directory: no directory entry in memory */ + dirp->cached = 0; + datap = NULL; + } + return datap; } /* Get next directory entry (internal) */ static WIN32_FIND_DATAW* dirent_next( - _WDIR *dirp) + _WDIR *dirp) { - WIN32_FIND_DATAW *p; - - /* Get next directory entry */ - if (dirp->cached != 0) { - - /* A valid directory entry already in memory */ - p = &dirp->data; - dirp->cached = 0; - - } else if (dirp->handle != INVALID_HANDLE_VALUE) { - - /* Get the next directory entry from stream */ - if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { - /* Got a file */ - p = &dirp->data; - } else { - /* The very last entry has been processed or an error occured */ - FindClose (dirp->handle); - dirp->handle = INVALID_HANDLE_VALUE; - p = NULL; - } - - } else { - - /* End of directory stream reached */ - p = NULL; - + WIN32_FIND_DATAW *p; + /* Get next directory entry */ + if (dirp->cached != 0) + { + /* A valid directory entry already in memory */ + p = &dirp->data; + dirp->cached = 0; + } + else if (dirp->handle != INVALID_HANDLE_VALUE) + { + /* Get the next directory entry from stream */ + if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) + { + /* Got a file */ + p = &dirp->data; } - - return p; + else + { + /* The very last entry has been processed or an error occured */ + FindClose (dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; + p = NULL; + } + } + else + { + /* End of directory stream reached */ + p = NULL; + } + return p; } /* @@ -575,60 +583,63 @@ dirent_next( */ static DIR* opendir( - const char *dirname) + const char *dirname) { - struct DIR *dirp; - int error; - - /* Must have directory name */ - if (dirname == NULL || dirname[0] == '\0') { - dirent_set_errno (ENOENT); - return NULL; - } - - /* Allocate memory for DIR structure */ - dirp = (DIR*) malloc (sizeof (struct DIR)); - if (dirp) { - wchar_t wname[PATH_MAX + 1]; - size_t n; - - /* Convert directory name to wide-character string */ - error = dirent_mbstowcs_s( - &n, wname, PATH_MAX + 1, dirname, PATH_MAX); - if (!error) { - - /* Open directory stream using wide-character name */ - dirp->wdirp = _wopendir (wname); - if (dirp->wdirp) { - /* Directory stream opened */ - error = 0; - } else { - /* Failed to open directory stream */ - error = 1; - } - - } else { - /* - * Cannot convert file name to wide-character string. This - * occurs if the string contains invalid multi-byte sequences or - * the output buffer is too small to contain the resulting - * string. - */ - error = 1; - } - - } else { - /* Cannot allocate DIR structure */ + struct DIR *dirp; + int error; + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') + { + dirent_set_errno (ENOENT); + return NULL; + } + /* Allocate memory for DIR structure */ + dirp = (DIR*) malloc (sizeof (struct DIR)); + if (dirp) + { + wchar_t wname[PATH_MAX + 1]; + size_t n; + /* Convert directory name to wide-character string */ + error = dirent_mbstowcs_s( + &n, wname, PATH_MAX + 1, dirname, PATH_MAX); + if (!error) + { + /* Open directory stream using wide-character name */ + dirp->wdirp = _wopendir (wname); + if (dirp->wdirp) + { + /* Directory stream opened */ + error = 0; + } + else + { + /* Failed to open directory stream */ error = 1; + } } - - /* Clean up in case of error */ - if (error && dirp) { - free (dirp); - dirp = NULL; + else + { + /* + * Cannot convert file name to wide-character string. This + * occurs if the string contains invalid multi-byte sequences or + * the output buffer is too small to contain the resulting + * string. + */ + error = 1; } - - return dirp; + } + else + { + /* Cannot allocate DIR structure */ + error = 1; + } + /* Clean up in case of error */ + if (error && dirp) + { + free (dirp); + dirp = NULL; + } + return dirp; } /* @@ -646,83 +657,86 @@ opendir( */ static struct dirent* readdir( - DIR *dirp) + DIR *dirp) { - WIN32_FIND_DATAW *datap; - struct dirent *entp; + WIN32_FIND_DATAW *datap; + struct dirent *entp; - /* Read next directory entry */ - datap = dirent_next (dirp->wdirp); - if (datap) { - size_t n; - int error; - - /* Attempt to convert file name to multi-byte string */ - error = dirent_wcstombs_s( - &n, dirp->ent.d_name, MAX_PATH + 1, datap->cFileName, MAX_PATH); - - /* - * If the file name cannot be represented by a multi-byte string, - * then attempt to use old 8+3 file name. This allows traditional - * Unix-code to access some file names despite of unicode - * characters, although file names may seem unfamiliar to the user. - * - * Be ware that the code below cannot come up with a short file - * name unless the file system provides one. At least - * VirtualBox shared folders fail to do this. - */ - if (error && datap->cAlternateFileName[0] != '\0') { - error = dirent_wcstombs_s( + /* Read next directory entry */ + datap = dirent_next (dirp->wdirp); + if (datap) + { + size_t n; + int error; + /* Attempt to convert file name to multi-byte string */ + error = dirent_wcstombs_s( + &n, dirp->ent.d_name, MAX_PATH + 1, datap->cFileName, MAX_PATH); + /* + * If the file name cannot be represented by a multi-byte string, + * then attempt to use old 8+3 file name. This allows traditional + * Unix-code to access some file names despite of unicode + * characters, although file names may seem unfamiliar to the user. + * + * Be ware that the code below cannot come up with a short file + * name unless the file system provides one. At least + * VirtualBox shared folders fail to do this. + */ + if (error && datap->cAlternateFileName[0] != '\0') + { + error = dirent_wcstombs_s( &n, dirp->ent.d_name, MAX_PATH + 1, datap->cAlternateFileName, sizeof (datap->cAlternateFileName) / - sizeof (datap->cAlternateFileName[0])); - } - - if (!error) { - DWORD attr; - - /* Initialize directory entry for return */ - entp = &dirp->ent; - - /* Length of file name excluding zero terminator */ - entp->d_namlen = n - 1; - - /* File attributes */ - attr = datap->dwFileAttributes; - if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { - entp->d_type = DT_CHR; - } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { - entp->d_type = DT_DIR; - } else { - entp->d_type = DT_REG; - } - - /* Reset dummy fields */ - entp->d_ino = 0; - entp->d_reclen = sizeof (struct dirent); - - } else { - /* - * Cannot convert file name to multi-byte string so construct - * an errornous directory entry and return that. Note that - * we cannot return NULL as that would stop the processing - * of directory entries completely. - */ - entp = &dirp->ent; - entp->d_name[0] = '?'; - entp->d_name[1] = '\0'; - entp->d_namlen = 1; - entp->d_type = DT_UNKNOWN; - entp->d_ino = 0; - entp->d_reclen = 0; - } - - } else { - /* No more directory entries */ - entp = NULL; + sizeof (datap->cAlternateFileName[0])); } + if (!error) + { + DWORD attr; + /* Initialize directory entry for return */ + entp = &dirp->ent; + /* Length of file name excluding zero terminator */ + entp->d_namlen = n - 1; + /* File attributes */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) + { + entp->d_type = DT_CHR; + } + else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) + { + entp->d_type = DT_DIR; + } + else + { + entp->d_type = DT_REG; + } + /* Reset dummy fields */ + entp->d_ino = 0; + entp->d_reclen = sizeof (struct dirent); + } + else + { + /* + * Cannot convert file name to multi-byte string so construct + * an errornous directory entry and return that. Note that + * we cannot return NULL as that would stop the processing + * of directory entries completely. + */ + entp = &dirp->ent; + entp->d_name[0] = '?'; + entp->d_name[1] = '\0'; + entp->d_namlen = 1; + entp->d_type = DT_UNKNOWN; + entp->d_ino = 0; + entp->d_reclen = 0; + } + } + else + { + /* No more directory entries */ + entp = NULL; + } - return entp; + return entp; } /* @@ -730,26 +744,24 @@ readdir( */ static int closedir( - DIR *dirp) + DIR *dirp) { - int ok; - if (dirp) { - - /* Close wide-character directory stream */ - ok = _wclosedir (dirp->wdirp); - dirp->wdirp = NULL; - - /* Release multi-byte character version */ - free (dirp); - - } else { - - /* Invalid directory stream */ - dirent_set_errno (EBADF); - ok = /*failure*/-1; - - } - return ok; + int ok; + if (dirp) + { + /* Close wide-character directory stream */ + ok = _wclosedir (dirp->wdirp); + dirp->wdirp = NULL; + /* Release multi-byte character version */ + free (dirp); + } + else + { + /* Invalid directory stream */ + dirent_set_errno (EBADF); + ok = /*failure*/-1; + } + return ok; } /* @@ -757,127 +769,107 @@ closedir( */ static void rewinddir( - DIR* dirp) + DIR* dirp) { - /* Rewind wide-character string directory stream */ - _wrewinddir (dirp->wdirp); + /* Rewind wide-character string directory stream */ + _wrewinddir (dirp->wdirp); } /* Convert multi-byte string to wide character string */ static int dirent_mbstowcs_s( - size_t *pReturnValue, - wchar_t *wcstr, - size_t sizeInWords, - const char *mbstr, - size_t count) + size_t *pReturnValue, + wchar_t *wcstr, + size_t sizeInWords, + const char *mbstr, + size_t count) { - int error; - + int error; #if defined(_MSC_VER) && _MSC_VER >= 1400 - - /* Microsoft Visual Studio 2005 or later */ - error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); - + /* Microsoft Visual Studio 2005 or later */ + error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); #else - - /* Older Visual Studio or non-Microsoft compiler */ - size_t n; - - /* Convert to wide-character string */ - n = mbstowcs (wcstr, mbstr, count); - if (n < sizeInWords) { - - /* Zero-terminate output buffer */ - if (wcstr) { - wcstr[n] = 0; - } - - /* Length of resuting multi-byte string WITH zero terminator */ - if (pReturnValue) { - *pReturnValue = n + 1; - } - - /* Success */ - error = 0; - - } else { - - /* Could not convert string */ - error = 1; - + /* Older Visual Studio or non-Microsoft compiler */ + size_t n; + /* Convert to wide-character string */ + n = mbstowcs (wcstr, mbstr, count); + if (n < sizeInWords) + { + /* Zero-terminate output buffer */ + if (wcstr) + { + wcstr[n] = 0; } - + /* Length of resuting multi-byte string WITH zero terminator */ + if (pReturnValue) + { + *pReturnValue = n + 1; + } + /* Success */ + error = 0; + } + else + { + /* Could not convert string */ + error = 1; + } #endif - - return error; + return error; } /* Convert wide-character string to multi-byte string */ static int dirent_wcstombs_s( - size_t *pReturnValue, - char *mbstr, - size_t sizeInBytes, - const wchar_t *wcstr, - size_t count) + size_t *pReturnValue, + char *mbstr, + size_t sizeInBytes, + const wchar_t *wcstr, + size_t count) { - int error; - + int error; #if defined(_MSC_VER) && _MSC_VER >= 1400 - - /* Microsoft Visual Studio 2005 or later */ - error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); - + /* Microsoft Visual Studio 2005 or later */ + error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); #else - - /* Older Visual Studio or non-Microsoft compiler */ - size_t n; - - /* Convert to multi-byte string */ - n = wcstombs (mbstr, wcstr, count); - if (n < sizeInBytes) { - - /* Zero-terminate output buffer */ - if (mbstr) { - mbstr[n] = '\0'; - } - - /* Lenght of resulting multi-bytes string WITH zero-terminator */ - if (pReturnValue) { - *pReturnValue = n + 1; - } - - /* Success */ - error = 0; - - } else { - - /* Cannot convert string */ - error = 1; - + /* Older Visual Studio or non-Microsoft compiler */ + size_t n; + /* Convert to multi-byte string */ + n = wcstombs (mbstr, wcstr, count); + if (n < sizeInBytes) + { + /* Zero-terminate output buffer */ + if (mbstr) + { + mbstr[n] = '\0'; } - + /* Lenght of resulting multi-bytes string WITH zero-terminator */ + if (pReturnValue) + { + *pReturnValue = n + 1; + } + /* Success */ + error = 0; + } + else + { + /* Cannot convert string */ + error = 1; + } #endif - - return error; + return error; } /* Set errno variable */ static void dirent_set_errno( - int error) + int error) { #if defined(_MSC_VER) - - /* Microsoft Visual Studio */ - _set_errno (error); - + /* Microsoft Visual Studio */ + _set_errno (error); #else - - /* Non-Microsoft compiler */ - errno = error; - + /* Non-Microsoft compiler */ + errno = error; #endif } diff --git a/src/openalpr/support/windows/utils.h b/src/openalpr/support/windows/utils.h index 0049234..a7409f0 100644 --- a/src/openalpr/support/windows/utils.h +++ b/src/openalpr/support/windows/utils.h @@ -3,5 +3,5 @@ static inline double round(double val) { - return floor(val + 0.5); + return floor(val + 0.5); } diff --git a/src/openalpr/trex.h b/src/openalpr/trex.h index 2ba378f..cb49690 100644 --- a/src/openalpr/trex.h +++ b/src/openalpr/trex.h @@ -51,9 +51,10 @@ typedef unsigned int TRexBool; typedef struct TRex TRex; -typedef struct { - const TRexChar *begin; - int len; +typedef struct +{ + const TRexChar *begin; + int len; } TRexMatch; TREX_API TRex *trex_compile(const TRexChar *pattern,const TRexChar **error); diff --git a/src/openalpr/utility.cpp b/src/openalpr/utility.cpp index 595e314..96b0323 100644 --- a/src/openalpr/utility.cpp +++ b/src/openalpr/utility.cpp @@ -17,12 +17,8 @@ * along with this program. If not, see . */ - - - #include "utility.h" - Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, int maxY) { Rect expandedRegion = Rect(original); @@ -48,22 +44,22 @@ Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, i Mat drawImageDashboard(vector images, int imageType, int numColumns) { - int numRows = ceil((float) images.size() / (float) numColumns); + int numRows = ceil((float) images.size() / (float) numColumns); - Mat dashboard(Size(images[0].cols * numColumns, images[0].rows * numRows), imageType); + Mat dashboard(Size(images[0].cols * numColumns, images[0].rows * numRows), imageType); - for (int i = 0; i < numColumns * numRows; i++) - { - if (i < images.size()) - images[i].copyTo(dashboard(Rect((i%numColumns) * images[i].cols, floor((float) i/numColumns) * images[i].rows, images[i].cols, images[i].rows))); - else - { - Mat black = Mat::zeros(images[0].size(), imageType); - black.copyTo(dashboard(Rect((i%numColumns) * images[0].cols, floor((float) i/numColumns) * images[0].rows, images[0].cols, images[0].rows))); - } - } + for (int i = 0; i < numColumns * numRows; i++) + { + if (i < images.size()) + images[i].copyTo(dashboard(Rect((i%numColumns) * images[i].cols, floor((float) i/numColumns) * images[i].rows, images[i].cols, images[i].rows))); + else + { + Mat black = Mat::zeros(images[0].size(), imageType); + black.copyTo(dashboard(Rect((i%numColumns) * images[0].cols, floor((float) i/numColumns) * images[0].rows, images[0].cols, images[0].rows))); + } + } - return dashboard; + return dashboard; } Mat addLabel(Mat input, string label) @@ -90,15 +86,13 @@ Mat addLabel(Mat input, string label) return newImage; } - - void drawAndWait(cv::Mat* frame) { cv::imshow("Temp Window", *frame); while (cv::waitKey(50) == -1) { - // loop + // loop } cv::destroyWindow("Temp Window"); @@ -137,7 +131,8 @@ vector produceThresholds(const Mat img_gray, Config* config) NiblackSauvolaWolfJolion (img_gray, thresholds[i++], WOLFJOLION, win, win, 0.05 + (k * 0.35)); bitwise_not(thresholds[i-1], thresholds[i-1]); - k = 1; win = 22; + k = 1; + win = 22; NiblackSauvolaWolfJolion (img_gray, thresholds[i++], WOLFJOLION, win, win, 0.05 + (k * 0.35)); bitwise_not(thresholds[i-1], thresholds[i-1]); //NiblackSauvolaWolfJolion (img_gray, thresholds[i++], WOLFJOLION, win, win, 0.05 + (k * 0.35)); @@ -151,11 +146,6 @@ vector produceThresholds(const Mat img_gray, Config* config) NiblackSauvolaWolfJolion (img_gray, thresholds[i++], SAUVOLA, 12, 12, 0.18 * k); bitwise_not(thresholds[i-1], thresholds[i-1]); - - - - - if (config->debugTiming) { timespec endTime; @@ -180,7 +170,6 @@ double median(int array[], int arraySize) return arraySize % 2 ? array[arraySize / 2] : (array[arraySize / 2 - 1] + array[arraySize / 2]) / 2; } - Mat equalizeBrightness(Mat img) { @@ -194,7 +183,6 @@ Mat equalizeBrightness(Mat img) normalize(img, img, 0, 255, NORM_MINMAX); img.convertTo(img, CV_8U); // convert back to unsigned int - return img; } @@ -218,18 +206,17 @@ void fillMask(Mat img, const Mat mask, Scalar color) if (m) { - for (int z = 0; z < 3; z++) - { - int prevVal = img.at(row, col)[z]; - img.at(row, col)[z] = ((int) color[z]) | prevVal; - } + for (int z = 0; z < 3; z++) + { + int prevVal = img.at(row, col)[z]; + img.at(row, col)[z] = ((int) color[z]) | prevVal; + } } } } } - void drawX(Mat img, Rect rect, Scalar color, int thickness) { Point tl(rect.x, rect.y); @@ -251,28 +238,26 @@ double distanceBetweenPoints(Point p1, Point p2) float angleBetweenPoints(Point p1, Point p2) { - int deltaY = p2.y - p1.y; - int deltaX = p2.x - p1.x; + int deltaY = p2.y - p1.y; + int deltaX = p2.x - p1.x; - return atan2((float) deltaY, (float) deltaX) * (180 / CV_PI); + return atan2((float) deltaY, (float) deltaX) * (180 / CV_PI); } - Size getSizeMaintainingAspect(Mat inputImg, int maxWidth, int maxHeight) { - float aspect = ((float) inputImg.cols) / ((float) inputImg.rows); + float aspect = ((float) inputImg.cols) / ((float) inputImg.rows); - if (maxWidth / aspect > maxHeight) - { - return Size(maxHeight * aspect, maxHeight); - } - else - { - return Size(maxWidth, maxWidth / aspect); - } + if (maxWidth / aspect > maxHeight) + { + return Size(maxHeight * aspect, maxHeight); + } + else + { + return Size(maxWidth, maxWidth / aspect); + } } - LineSegment::LineSegment() { init(0, 0, 0, 0); @@ -292,18 +277,19 @@ void LineSegment::init(int x1, int y1, int x2, int y2) this->p1 = Point(x1, y1); this->p2 = Point(x2, y2); - if (p2.x - p1.x == 0) - this->slope = 0.00000000001; - else - this->slope = (float) (p2.y - p1.y) / (float) (p2.x - p1.x); + if (p2.x - p1.x == 0) + this->slope = 0.00000000001; + else + this->slope = (float) (p2.y - p1.y) / (float) (p2.x - p1.x); - this->length = distanceBetweenPoints(p1, p2); + this->length = distanceBetweenPoints(p1, p2); - this->angle = angleBetweenPoints(p1, p2); + this->angle = angleBetweenPoints(p1, p2); } -bool LineSegment::isPointBelowLine( Point tp ){ - return ((p2.x - p1.x)*(tp.y - p1.y) - (p2.y - p1.y)*(tp.x - p1.x)) > 0; +bool LineSegment::isPointBelowLine( Point tp ) +{ + return ((p2.x - p1.x)*(tp.y - p1.y) - (p2.y - p1.y)*(tp.x - p1.x)) > 0; } float LineSegment::getPointAt(float x) @@ -328,41 +314,38 @@ Point LineSegment::closestPointOnSegmentTo(Point p) Point LineSegment::intersection(LineSegment line) { - float c1, c2; - float intersection_X = -1, intersection_Y= -1; + float c1, c2; + float intersection_X = -1, intersection_Y= -1; + c1 = p1.y - slope * p1.x; // which is same as y2 - slope * x2 - c1 = p1.y - slope * p1.x; // which is same as y2 - slope * x2 + c2 = line.p2.y - line.slope * line.p2.x; // which is same as y2 - slope * x2 - c2 = line.p2.y - line.slope * line.p2.x; // which is same as y2 - slope * x2 + if( (slope - line.slope) == 0) + { + //std::cout << "No Intersection between the lines" << endl; + } + else if (p1.x == p2.x) + { + // Line1 is vertical + return Point(p1.x, line.getPointAt(p1.x)); + } + else if (line.p1.x == line.p2.x) + { + // Line2 is vertical + return Point(line.p1.x, getPointAt(line.p1.x)); + } + else + { + intersection_X = (c2 - c1) / (slope - line.slope); + intersection_Y = slope * intersection_X + c1; - if( (slope - line.slope) == 0) - { - //std::cout << "No Intersection between the lines" << endl; - } - else if (p1.x == p2.x) - { - // Line1 is vertical - return Point(p1.x, line.getPointAt(p1.x)); - } - else if (line.p1.x == line.p2.x) - { - // Line2 is vertical - return Point(line.p1.x, getPointAt(line.p1.x)); - } - else - { - intersection_X = (c2 - c1) / (slope - line.slope); - intersection_Y = slope * intersection_X + c1; + } - } - - return Point(intersection_X, intersection_Y); + return Point(intersection_X, intersection_Y); } - - Point LineSegment::midpoint() { // Handle the case where the line is vertical @@ -381,17 +364,17 @@ Point LineSegment::midpoint() LineSegment LineSegment::getParallelLine(float distance) { - float diff_x = p2.x - p1.x; - float diff_y = p2.y - p1.y; - float angle = atan2( diff_x, diff_y); - float dist_x = distance * cos(angle); - float dist_y = -distance * sin(angle); + float diff_x = p2.x - p1.x; + float diff_y = p2.y - p1.y; + float angle = atan2( diff_x, diff_y); + float dist_x = distance * cos(angle); + float dist_y = -distance * sin(angle); - int offsetX = (int)round(dist_x); - int offsetY = (int)round(dist_y); + int offsetX = (int)round(dist_x); + int offsetY = (int)round(dist_y); - LineSegment result(p1.x + offsetX, p1.y + offsetY, - p2.x + offsetX, p2.y + offsetY); + LineSegment result(p1.x + offsetX, p1.y + offsetY, + p2.x + offsetX, p2.y + offsetY); - return result; + return result; } diff --git a/src/openalpr/utility.h b/src/openalpr/utility.h index 64cafce..74b8037 100644 --- a/src/openalpr/utility.h +++ b/src/openalpr/utility.h @@ -32,8 +32,8 @@ #include "constants.h" #include "support/timing.h" - #include "opencv2/highgui/highgui.hpp" - #include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/core/core.hpp" #include "binarize_wolf.h" #include @@ -41,13 +41,13 @@ - /* +/* struct LineSegment { - float x1; - float y1; - float x2; - float y2; + float x1; + float y1; + float x2; + float y2; }; */ @@ -61,7 +61,7 @@ class LineSegment float length; float angle; - // LineSegment(Point point1, Point point2); + // LineSegment(Point point1, Point point2); LineSegment(); LineSegment(int x1, int y1, int x2, int y2); LineSegment(Point p1, Point p2); @@ -90,30 +90,30 @@ class LineSegment }; - double median(int array[], int arraySize); +double median(int array[], int arraySize); - vector produceThresholds(const Mat img_gray, Config* config); +vector produceThresholds(const Mat img_gray, Config* config); - Mat drawImageDashboard(vector images, int imageType, int numColumns); +Mat drawImageDashboard(vector images, int imageType, int numColumns); - void displayImage(Config* config, string windowName, cv::Mat frame); - void drawAndWait(cv::Mat* frame); +void displayImage(Config* config, string windowName, cv::Mat frame); +void drawAndWait(cv::Mat* frame); - double distanceBetweenPoints(Point p1, Point p2); +double distanceBetweenPoints(Point p1, Point p2); - void drawRotatedRect(Mat* img, RotatedRect rect, Scalar color, int thickness); +void drawRotatedRect(Mat* img, RotatedRect rect, Scalar color, int thickness); - void drawX(Mat img, Rect rect, Scalar color, int thickness); - void fillMask(Mat img, const Mat mask, Scalar color); +void drawX(Mat img, Rect rect, Scalar color, int thickness); +void fillMask(Mat img, const Mat mask, Scalar color); - float angleBetweenPoints(Point p1, Point p2); +float angleBetweenPoints(Point p1, Point p2); - Size getSizeMaintainingAspect(Mat inputImg, int maxWidth, int maxHeight); +Size getSizeMaintainingAspect(Mat inputImg, int maxWidth, int maxHeight); - Mat equalizeBrightness(Mat img); +Mat equalizeBrightness(Mat img); - Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, int maxY); +Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, int maxY); - Mat addLabel(Mat input, string label); +Mat addLabel(Mat input, string label); #endif // UTILITY_H diff --git a/src/openalpr/verticalhistogram.cpp b/src/openalpr/verticalhistogram.cpp index ebe97b1..a125fac 100644 --- a/src/openalpr/verticalhistogram.cpp +++ b/src/openalpr/verticalhistogram.cpp @@ -23,8 +23,6 @@ VerticalHistogram::VerticalHistogram(Mat inputImage, Mat mask) { analyzeImage(inputImage, mask); - - } VerticalHistogram::~VerticalHistogram() @@ -33,42 +31,38 @@ VerticalHistogram::~VerticalHistogram() colHeights.clear(); } - void VerticalHistogram::analyzeImage(Mat inputImage, Mat mask) { - highestPeak = 0; - lowestValley = inputImage.rows; + highestPeak = 0; + lowestValley = inputImage.rows; + histoImg = Mat::zeros(inputImage.size(), CV_8U); - histoImg = Mat::zeros(inputImage.size(), CV_8U); + int columnCount; - int columnCount; + for (int col = 0; col < inputImage.cols; col++) + { + columnCount = 0; - for (int col = 0; col < inputImage.cols; col++) + for (int row = 0; row < inputImage.rows; row++) { - columnCount = 0; - - for (int row = 0; row < inputImage.rows; row++) - { - - if (inputImage.at(row, col) > 0 && mask.at(row, col) > 0) - columnCount++; - } - - - this->colHeights.push_back(columnCount); - - if (columnCount < lowestValley) - lowestValley = columnCount; - if (columnCount > highestPeak) - highestPeak = columnCount; - - - for (; columnCount > 0; columnCount--) - histoImg.at(inputImage.rows - columnCount, col) = 255; + if (inputImage.at(row, col) > 0 && mask.at(row, col) > 0) + columnCount++; } + this->colHeights.push_back(columnCount); + + if (columnCount < lowestValley) + lowestValley = columnCount; + if (columnCount > highestPeak) + highestPeak = columnCount; + + for (; columnCount > 0; columnCount--) + histoImg.at(inputImage.rows - columnCount, col) = 255; + + } + } int VerticalHistogram::getLocalMinimum(int leftX, int rightX) @@ -107,7 +101,7 @@ int VerticalHistogram::getLocalMaximum(int leftX, int rightX) int VerticalHistogram::getHeightAt(int x) { - return colHeights[x]; + return colHeights[x]; } void VerticalHistogram::findValleys() @@ -130,8 +124,7 @@ void VerticalHistogram::findValleys() if (aboveMidpoint) { if (colHeights[i] > relativePeakHeight) - relativePeakHeight = colHeights[i]; - + relativePeakHeight = colHeights[i]; prevDirection = FLAT; @@ -171,7 +164,7 @@ HistogramDirection VerticalHistogram::getHistogramDirection(int index) for (int i = index; i >= trailStartIndex; i--) { - trailingAverage += colHeights[i]; + trailingAverage += colHeights[i]; } trailingAverage = trailingAverage / ((float) (1 + index - trailStartIndex)); @@ -181,7 +174,6 @@ HistogramDirection VerticalHistogram::getHistogramDirection(int index) } forwardAverage = forwardAverage / ((float) (1 + forwardEndIndex - index)); - float diff = forwardAverage - trailingAverage; float minDiff = ((float) (highestPeak - lowestValley)) * 0.10; diff --git a/src/openalpr/verticalhistogram.h b/src/openalpr/verticalhistogram.h index c424b91..ce02962 100644 --- a/src/openalpr/verticalhistogram.h +++ b/src/openalpr/verticalhistogram.h @@ -29,10 +29,10 @@ using namespace std; struct Valley { - int startIndex; - int endIndex; - int width; - int pixelsWithin; + int startIndex; + int endIndex; + int width; + int pixelsWithin; }; enum HistogramDirection { RISING, FALLING, FLAT }; diff --git a/src/tclap/Arg.h b/src/tclap/Arg.h index 3945b19..ab051d3 100644 --- a/src/tclap/Arg.h +++ b/src/tclap/Arg.h @@ -54,7 +54,8 @@ typedef std::istrstream istringstream; #include "ArgTraits.h" #include "StandardTraits.h" -namespace TCLAP { +namespace TCLAP +{ /** * A virtual base class that defines the essential data for all arguments. @@ -63,331 +64,366 @@ namespace TCLAP { */ class Arg { - private: - /** - * Prevent accidental copying. - */ - Arg(const Arg& rhs); + private: + /** + * Prevent accidental copying. + */ + Arg(const Arg& rhs); - /** - * Prevent accidental copying. - */ - Arg& operator=(const Arg& rhs); + /** + * Prevent accidental copying. + */ + Arg& operator=(const Arg& rhs); - /** - * Indicates whether the rest of the arguments should be ignored. - */ - static bool& ignoreRestRef() { static bool ign = false; return ign; } + /** + * Indicates whether the rest of the arguments should be ignored. + */ + static bool& ignoreRestRef() + { + static bool ign = false; + return ign; + } - /** - * The delimiter that separates an argument flag/name from the - * value. - */ - static char& delimiterRef() { static char delim = ' '; return delim; } + /** + * The delimiter that separates an argument flag/name from the + * value. + */ + static char& delimiterRef() + { + static char delim = ' '; + return delim; + } - protected: + protected: - /** - * The single char flag used to identify the argument. - * This value (preceded by a dash {-}), can be used to identify - * an argument on the command line. The _flag can be blank, - * in fact this is how unlabeled args work. Unlabeled args must - * override appropriate functions to get correct handling. Note - * that the _flag does NOT include the dash as part of the flag. - */ - std::string _flag; + /** + * The single char flag used to identify the argument. + * This value (preceded by a dash {-}), can be used to identify + * an argument on the command line. The _flag can be blank, + * in fact this is how unlabeled args work. Unlabeled args must + * override appropriate functions to get correct handling. Note + * that the _flag does NOT include the dash as part of the flag. + */ + std::string _flag; - /** - * A single work namd indentifying the argument. - * This value (preceded by two dashed {--}) can also be used - * to identify an argument on the command line. Note that the - * _name does NOT include the two dashes as part of the _name. The - * _name cannot be blank. - */ - std::string _name; + /** + * A single work namd indentifying the argument. + * This value (preceded by two dashed {--}) can also be used + * to identify an argument on the command line. Note that the + * _name does NOT include the two dashes as part of the _name. The + * _name cannot be blank. + */ + std::string _name; - /** - * Description of the argument. - */ - std::string _description; + /** + * Description of the argument. + */ + std::string _description; - /** - * Indicating whether the argument is required. - */ - bool _required; + /** + * Indicating whether the argument is required. + */ + bool _required; - /** - * Label to be used in usage description. Normally set to - * "required", but can be changed when necessary. - */ - std::string _requireLabel; + /** + * Label to be used in usage description. Normally set to + * "required", but can be changed when necessary. + */ + std::string _requireLabel; - /** - * Indicates whether a value is required for the argument. - * Note that the value may be required but the argument/value - * combination may not be, as specified by _required. - */ - bool _valueRequired; + /** + * Indicates whether a value is required for the argument. + * Note that the value may be required but the argument/value + * combination may not be, as specified by _required. + */ + bool _valueRequired; - /** - * Indicates whether the argument has been set. - * Indicates that a value on the command line has matched the - * name/flag of this argument and the values have been set accordingly. - */ - bool _alreadySet; + /** + * Indicates whether the argument has been set. + * Indicates that a value on the command line has matched the + * name/flag of this argument and the values have been set accordingly. + */ + bool _alreadySet; - /** - * A pointer to a vistitor object. - * The visitor allows special handling to occur as soon as the - * argument is matched. This defaults to NULL and should not - * be used unless absolutely necessary. - */ - Visitor* _visitor; + /** + * A pointer to a vistitor object. + * The visitor allows special handling to occur as soon as the + * argument is matched. This defaults to NULL and should not + * be used unless absolutely necessary. + */ + Visitor* _visitor; - /** - * Whether this argument can be ignored, if desired. - */ - bool _ignoreable; + /** + * Whether this argument can be ignored, if desired. + */ + bool _ignoreable; - /** - * Indicates that the arg was set as part of an XOR and not on the - * command line. - */ - bool _xorSet; + /** + * Indicates that the arg was set as part of an XOR and not on the + * command line. + */ + bool _xorSet; - bool _acceptsMultipleValues; + bool _acceptsMultipleValues; - /** - * Performs the special handling described by the Vistitor. - */ - void _checkWithVisitor() const; + /** + * Performs the special handling described by the Vistitor. + */ + void _checkWithVisitor() const; - /** - * Primary constructor. YOU (yes you) should NEVER construct an Arg - * directly, this is a base class that is extended by various children - * that are meant to be used. Use SwitchArg, ValueArg, MultiArg, - * UnlabeledValueArg, or UnlabeledMultiArg instead. - * - * \param flag - The flag identifying the argument. - * \param name - The name identifying the argument. - * \param desc - The description of the argument, used in the usage. - * \param req - Whether the argument is required. - * \param valreq - Whether the a value is required for the argument. - * \param v - The visitor checked by the argument. Defaults to NULL. - */ - Arg( const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, - bool valreq, - Visitor* v = NULL ); + /** + * Primary constructor. YOU (yes you) should NEVER construct an Arg + * directly, this is a base class that is extended by various children + * that are meant to be used. Use SwitchArg, ValueArg, MultiArg, + * UnlabeledValueArg, or UnlabeledMultiArg instead. + * + * \param flag - The flag identifying the argument. + * \param name - The name identifying the argument. + * \param desc - The description of the argument, used in the usage. + * \param req - Whether the argument is required. + * \param valreq - Whether the a value is required for the argument. + * \param v - The visitor checked by the argument. Defaults to NULL. + */ + Arg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + bool valreq, + Visitor* v = NULL ); - public: - /** - * Destructor. - */ - virtual ~Arg(); + public: + /** + * Destructor. + */ + virtual ~Arg(); - /** - * Adds this to the specified list of Args. - * \param argList - The list to add this to. - */ - virtual void addToList( std::list& argList ) const; + /** + * Adds this to the specified list of Args. + * \param argList - The list to add this to. + */ + virtual void addToList( std::list& argList ) const; - /** - * Begin ignoring arguments since the "--" argument was specified. - */ - static void beginIgnoring() { ignoreRestRef() = true; } + /** + * Begin ignoring arguments since the "--" argument was specified. + */ + static void beginIgnoring() + { + ignoreRestRef() = true; + } - /** - * Whether to ignore the rest. - */ - static bool ignoreRest() { return ignoreRestRef(); } + /** + * Whether to ignore the rest. + */ + static bool ignoreRest() + { + return ignoreRestRef(); + } - /** - * The delimiter that separates an argument flag/name from the - * value. - */ - static char delimiter() { return delimiterRef(); } + /** + * The delimiter that separates an argument flag/name from the + * value. + */ + static char delimiter() + { + return delimiterRef(); + } - /** - * The char used as a place holder when SwitchArgs are combined. - * Currently set to the bell char (ASCII 7). - */ - static char blankChar() { return (char)7; } + /** + * The char used as a place holder when SwitchArgs are combined. + * Currently set to the bell char (ASCII 7). + */ + static char blankChar() + { + return (char)7; + } - /** - * The char that indicates the beginning of a flag. Defaults to '-', but - * clients can define TCLAP_FLAGSTARTCHAR to override. - */ + /** + * The char that indicates the beginning of a flag. Defaults to '-', but + * clients can define TCLAP_FLAGSTARTCHAR to override. + */ #ifndef TCLAP_FLAGSTARTCHAR #define TCLAP_FLAGSTARTCHAR '-' #endif - static char flagStartChar() { return TCLAP_FLAGSTARTCHAR; } + static char flagStartChar() + { + return TCLAP_FLAGSTARTCHAR; + } - /** - * The sting that indicates the beginning of a flag. Defaults to "-", but - * clients can define TCLAP_FLAGSTARTSTRING to override. Should be the same - * as TCLAP_FLAGSTARTCHAR. - */ + /** + * The sting that indicates the beginning of a flag. Defaults to "-", but + * clients can define TCLAP_FLAGSTARTSTRING to override. Should be the same + * as TCLAP_FLAGSTARTCHAR. + */ #ifndef TCLAP_FLAGSTARTSTRING #define TCLAP_FLAGSTARTSTRING "-" #endif - static const std::string flagStartString() { return TCLAP_FLAGSTARTSTRING; } + static const std::string flagStartString() + { + return TCLAP_FLAGSTARTSTRING; + } - /** - * The sting that indicates the beginning of a name. Defaults to "--", but - * clients can define TCLAP_NAMESTARTSTRING to override. - */ + /** + * The sting that indicates the beginning of a name. Defaults to "--", but + * clients can define TCLAP_NAMESTARTSTRING to override. + */ #ifndef TCLAP_NAMESTARTSTRING #define TCLAP_NAMESTARTSTRING "--" #endif - static const std::string nameStartString() { return TCLAP_NAMESTARTSTRING; } + static const std::string nameStartString() + { + return TCLAP_NAMESTARTSTRING; + } - /** - * The name used to identify the ignore rest argument. - */ - static const std::string ignoreNameString() { return "ignore_rest"; } + /** + * The name used to identify the ignore rest argument. + */ + static const std::string ignoreNameString() + { + return "ignore_rest"; + } - /** - * Sets the delimiter for all arguments. - * \param c - The character that delimits flags/names from values. - */ - static void setDelimiter( char c ) { delimiterRef() = c; } + /** + * Sets the delimiter for all arguments. + * \param c - The character that delimits flags/names from values. + */ + static void setDelimiter( char c ) + { + delimiterRef() = c; + } - /** - * Pure virtual method meant to handle the parsing and value assignment - * of the string on the command line. - * \param i - Pointer the the current argument in the list. - * \param args - Mutable list of strings. What is - * passed in from main. - */ - virtual bool processArg(int *i, std::vector& args) = 0; + /** + * Pure virtual method meant to handle the parsing and value assignment + * of the string on the command line. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. What is + * passed in from main. + */ + virtual bool processArg(int *i, std::vector& args) = 0; - /** - * Operator ==. - * Equality operator. Must be virtual to handle unlabeled args. - * \param a - The Arg to be compared to this. - */ - virtual bool operator==(const Arg& a) const; + /** + * Operator ==. + * Equality operator. Must be virtual to handle unlabeled args. + * \param a - The Arg to be compared to this. + */ + virtual bool operator==(const Arg& a) const; - /** - * Returns the argument flag. - */ - const std::string& getFlag() const; + /** + * Returns the argument flag. + */ + const std::string& getFlag() const; - /** - * Returns the argument name. - */ - const std::string& getName() const; + /** + * Returns the argument name. + */ + const std::string& getName() const; - /** - * Returns the argument description. - */ - std::string getDescription() const; + /** + * Returns the argument description. + */ + std::string getDescription() const; - /** - * Indicates whether the argument is required. - */ - virtual bool isRequired() const; + /** + * Indicates whether the argument is required. + */ + virtual bool isRequired() const; - /** - * Sets _required to true. This is used by the XorHandler. - * You really have no reason to ever use it. - */ - void forceRequired(); + /** + * Sets _required to true. This is used by the XorHandler. + * You really have no reason to ever use it. + */ + void forceRequired(); - /** - * Sets the _alreadySet value to true. This is used by the XorHandler. - * You really have no reason to ever use it. - */ - void xorSet(); + /** + * Sets the _alreadySet value to true. This is used by the XorHandler. + * You really have no reason to ever use it. + */ + void xorSet(); - /** - * Indicates whether a value must be specified for argument. - */ - bool isValueRequired() const; + /** + * Indicates whether a value must be specified for argument. + */ + bool isValueRequired() const; - /** - * Indicates whether the argument has already been set. Only true - * if the arg has been matched on the command line. - */ - bool isSet() const; + /** + * Indicates whether the argument has already been set. Only true + * if the arg has been matched on the command line. + */ + bool isSet() const; - /** - * Indicates whether the argument can be ignored, if desired. - */ - bool isIgnoreable() const; + /** + * Indicates whether the argument can be ignored, if desired. + */ + bool isIgnoreable() const; - /** - * A method that tests whether a string matches this argument. - * This is generally called by the processArg() method. This - * method could be re-implemented by a child to change how - * arguments are specified on the command line. - * \param s - The string to be compared to the flag/name to determine - * whether the arg matches. - */ - virtual bool argMatches( const std::string& s ) const; + /** + * A method that tests whether a string matches this argument. + * This is generally called by the processArg() method. This + * method could be re-implemented by a child to change how + * arguments are specified on the command line. + * \param s - The string to be compared to the flag/name to determine + * whether the arg matches. + */ + virtual bool argMatches( const std::string& s ) const; - /** - * Returns a simple string representation of the argument. - * Primarily for debugging. - */ - virtual std::string toString() const; + /** + * Returns a simple string representation of the argument. + * Primarily for debugging. + */ + virtual std::string toString() const; - /** - * Returns a short ID for the usage. - * \param valueId - The value used in the id. - */ - virtual std::string shortID( const std::string& valueId = "val" ) const; + /** + * Returns a short ID for the usage. + * \param valueId - The value used in the id. + */ + virtual std::string shortID( const std::string& valueId = "val" ) const; - /** - * Returns a long ID for the usage. - * \param valueId - The value used in the id. - */ - virtual std::string longID( const std::string& valueId = "val" ) const; + /** + * Returns a long ID for the usage. + * \param valueId - The value used in the id. + */ + virtual std::string longID( const std::string& valueId = "val" ) const; - /** - * Trims a value off of the flag. - * \param flag - The string from which the flag and value will be - * trimmed. Contains the flag once the value has been trimmed. - * \param value - Where the value trimmed from the string will - * be stored. - */ - virtual void trimFlag( std::string& flag, std::string& value ) const; + /** + * Trims a value off of the flag. + * \param flag - The string from which the flag and value will be + * trimmed. Contains the flag once the value has been trimmed. + * \param value - Where the value trimmed from the string will + * be stored. + */ + virtual void trimFlag( std::string& flag, std::string& value ) const; - /** - * Checks whether a given string has blank chars, indicating that - * it is a combined SwitchArg. If so, return true, otherwise return - * false. - * \param s - string to be checked. - */ - bool _hasBlanks( const std::string& s ) const; + /** + * Checks whether a given string has blank chars, indicating that + * it is a combined SwitchArg. If so, return true, otherwise return + * false. + * \param s - string to be checked. + */ + bool _hasBlanks( const std::string& s ) const; - /** - * Sets the requireLabel. Used by XorHandler. You shouldn't ever - * use this. - * \param s - Set the requireLabel to this value. - */ - void setRequireLabel( const std::string& s ); + /** + * Sets the requireLabel. Used by XorHandler. You shouldn't ever + * use this. + * \param s - Set the requireLabel to this value. + */ + void setRequireLabel( const std::string& s ); - /** - * Used for MultiArgs and XorHandler to determine whether args - * can still be set. - */ - virtual bool allowMore(); + /** + * Used for MultiArgs and XorHandler to determine whether args + * can still be set. + */ + virtual bool allowMore(); - /** - * Use by output classes to determine whether an Arg accepts - * multiple values. - */ - virtual bool acceptsMultipleValues(); + /** + * Use by output classes to determine whether an Arg accepts + * multiple values. + */ + virtual bool acceptsMultipleValues(); - /** - * Clears the Arg object and allows it to be reused by new - * command lines. - */ - virtual void reset(); + /** + * Clears the Arg object and allows it to be reused by new + * command lines. + */ + virtual void reset(); }; /** @@ -414,32 +450,27 @@ typedef std::list::iterator VisitorListIterator; template void ExtractValue(T &destVal, const std::string& strVal, ValueLike vl) { - static_cast(vl); // Avoid warning about unused vl - std::istringstream is(strVal); - - int valuesRead = 0; - while ( is.good() ) { - if ( is.peek() != EOF ) + static_cast(vl); // Avoid warning about unused vl + std::istringstream is(strVal); + int valuesRead = 0; + while ( is.good() ) + { + if ( is.peek() != EOF ) #ifdef TCLAP_SETBASE_ZERO - is >> std::setbase(0) >> destVal; + is >> std::setbase(0) >> destVal; #else - is >> destVal; + is >> destVal; #endif - else - break; - - valuesRead++; - } - - if ( is.fail() ) - throw( ArgParseException("Couldn't read argument value " - "from string '" + strVal + "'")); - - - if ( valuesRead > 1 ) - throw( ArgParseException("More than one valid value parsed from " - "string '" + strVal + "'")); - + else + break; + valuesRead++; + } + if ( is.fail() ) + throw( ArgParseException("Couldn't read argument value " + "from string '" + strVal + "'")); + if ( valuesRead > 1 ) + throw( ArgParseException("More than one valid value parsed from " + "string '" + strVal + "'")); } /* @@ -451,8 +482,8 @@ ExtractValue(T &destVal, const std::string& strVal, ValueLike vl) template void ExtractValue(T &destVal, const std::string& strVal, StringLike sl) { - static_cast(sl); // Avoid warning about unused sl - SetString(destVal, strVal); + static_cast(sl); // Avoid warning about unused sl + SetString(destVal, strVal); } ////////////////////////////////////////////////////////////////////// @@ -460,11 +491,11 @@ ExtractValue(T &destVal, const std::string& strVal, StringLike sl) ////////////////////////////////////////////////////////////////////// inline Arg::Arg(const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, - bool valreq, - Visitor* v) : + const std::string& name, + const std::string& desc, + bool req, + bool valreq, + Visitor* v) : _flag(flag), _name(name), _description(desc), @@ -477,141 +508,137 @@ inline Arg::Arg(const std::string& flag, _xorSet(false), _acceptsMultipleValues(false) { - if ( _flag.length() > 1 ) - throw(SpecificationException( - "Argument flag can only be one character long", toString() ) ); - - if ( _name != ignoreNameString() && - ( _flag == Arg::flagStartString() || - _flag == Arg::nameStartString() || - _flag == " " ) ) - throw(SpecificationException("Argument flag cannot be either '" + - Arg::flagStartString() + "' or '" + - Arg::nameStartString() + "' or a space.", - toString() ) ); - - if ( ( _name.substr( 0, Arg::flagStartString().length() ) == Arg::flagStartString() ) || - ( _name.substr( 0, Arg::nameStartString().length() ) == Arg::nameStartString() ) || - ( _name.find( " ", 0 ) != std::string::npos ) ) - throw(SpecificationException("Argument name begin with either '" + - Arg::flagStartString() + "' or '" + - Arg::nameStartString() + "' or space.", - toString() ) ); - + if ( _flag.length() > 1 ) + throw(SpecificationException( + "Argument flag can only be one character long", toString() ) ); + if ( _name != ignoreNameString() && + ( _flag == Arg::flagStartString() || + _flag == Arg::nameStartString() || + _flag == " " ) ) + throw(SpecificationException("Argument flag cannot be either '" + + Arg::flagStartString() + "' or '" + + Arg::nameStartString() + "' or a space.", + toString() ) ); + if ( ( _name.substr( 0, Arg::flagStartString().length() ) == Arg::flagStartString() ) || + ( _name.substr( 0, Arg::nameStartString().length() ) == Arg::nameStartString() ) || + ( _name.find( " ", 0 ) != std::string::npos ) ) + throw(SpecificationException("Argument name begin with either '" + + Arg::flagStartString() + "' or '" + + Arg::nameStartString() + "' or space.", + toString() ) ); } inline Arg::~Arg() { } inline std::string Arg::shortID( const std::string& valueId ) const { - std::string id = ""; - - if ( _flag != "" ) - id = Arg::flagStartString() + _flag; - else - id = Arg::nameStartString() + _name; - - if ( _valueRequired ) - id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">"; - - if ( !_required ) - id = "[" + id + "]"; - - return id; + std::string id = ""; + if ( _flag != "" ) + id = Arg::flagStartString() + _flag; + else + id = Arg::nameStartString() + _name; + if ( _valueRequired ) + id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">"; + if ( !_required ) + id = "[" + id + "]"; + return id; } inline std::string Arg::longID( const std::string& valueId ) const { - std::string id = ""; - - if ( _flag != "" ) - { - id += Arg::flagStartString() + _flag; - - if ( _valueRequired ) - id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">"; - - id += ", "; - } - - id += Arg::nameStartString() + _name; - - if ( _valueRequired ) - id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">"; - - return id; - + std::string id = ""; + if ( _flag != "" ) + { + id += Arg::flagStartString() + _flag; + if ( _valueRequired ) + id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">"; + id += ", "; + } + id += Arg::nameStartString() + _name; + if ( _valueRequired ) + id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">"; + return id; } inline bool Arg::operator==(const Arg& a) const { - if ( ( _flag != "" && _flag == a._flag ) || _name == a._name) - return true; - else - return false; + if ( ( _flag != "" && _flag == a._flag ) || _name == a._name) + return true; + else + return false; } inline std::string Arg::getDescription() const { - std::string desc = ""; - if ( _required ) - desc = "(" + _requireLabel + ") "; - + std::string desc = ""; + if ( _required ) + desc = "(" + _requireLabel + ") "; // if ( _valueRequired ) // desc += "(value required) "; - - desc += _description; - return desc; + desc += _description; + return desc; } -inline const std::string& Arg::getFlag() const { return _flag; } +inline const std::string& Arg::getFlag() const +{ + return _flag; +} -inline const std::string& Arg::getName() const { return _name; } +inline const std::string& Arg::getName() const +{ + return _name; +} -inline bool Arg::isRequired() const { return _required; } +inline bool Arg::isRequired() const +{ + return _required; +} -inline bool Arg::isValueRequired() const { return _valueRequired; } +inline bool Arg::isValueRequired() const +{ + return _valueRequired; +} inline bool Arg::isSet() const { - if ( _alreadySet && !_xorSet ) - return true; - else - return false; + if ( _alreadySet && !_xorSet ) + return true; + else + return false; } -inline bool Arg::isIgnoreable() const { return _ignoreable; } +inline bool Arg::isIgnoreable() const +{ + return _ignoreable; +} inline void Arg::setRequireLabel( const std::string& s) { - _requireLabel = s; + _requireLabel = s; } inline bool Arg::argMatches( const std::string& argFlag ) const { - if ( ( argFlag == Arg::flagStartString() + _flag && _flag != "" ) || - argFlag == Arg::nameStartString() + _name ) - return true; - else - return false; + if ( ( argFlag == Arg::flagStartString() + _flag && _flag != "" ) || + argFlag == Arg::nameStartString() + _name ) + return true; + else + return false; } inline std::string Arg::toString() const { - std::string s = ""; - - if ( _flag != "" ) - s += Arg::flagStartString() + _flag + " "; - - s += "(" + Arg::nameStartString() + _name + ")"; - - return s; + std::string s = ""; + if ( _flag != "" ) + s += Arg::flagStartString() + _flag + " "; + s += "(" + Arg::nameStartString() + _name + ")"; + return s; } inline void Arg::_checkWithVisitor() const { - if ( _visitor != NULL ) - _visitor->visit(); + if ( _visitor != NULL ) + _visitor->visit(); } /** @@ -619,20 +646,18 @@ inline void Arg::_checkWithVisitor() const */ inline void Arg::trimFlag(std::string& flag, std::string& value) const { - int stop = 0; - for ( int i = 0; static_cast(i) < flag.length(); i++ ) - if ( flag[i] == Arg::delimiter() ) - { - stop = i; - break; - } - - if ( stop > 1 ) - { - value = flag.substr(stop+1); - flag = flag.substr(0,stop); - } - + int stop = 0; + for ( int i = 0; static_cast(i) < flag.length(); i++ ) + if ( flag[i] == Arg::delimiter() ) + { + stop = i; + break; + } + if ( stop > 1 ) + { + value = flag.substr(stop+1); + flag = flag.substr(0,stop); + } } /** @@ -640,22 +665,21 @@ inline void Arg::trimFlag(std::string& flag, std::string& value) const */ inline bool Arg::_hasBlanks( const std::string& s ) const { - for ( int i = 1; static_cast(i) < s.length(); i++ ) - if ( s[i] == Arg::blankChar() ) - return true; - - return false; + for ( int i = 1; static_cast(i) < s.length(); i++ ) + if ( s[i] == Arg::blankChar() ) + return true; + return false; } inline void Arg::forceRequired() { - _required = true; + _required = true; } inline void Arg::xorSet() { - _alreadySet = true; - _xorSet = true; + _alreadySet = true; + _xorSet = true; } /** @@ -663,23 +687,23 @@ inline void Arg::xorSet() */ inline void Arg::addToList( std::list& argList ) const { - argList.push_front( const_cast(this) ); + argList.push_front( const_cast(this) ); } inline bool Arg::allowMore() { - return false; + return false; } inline bool Arg::acceptsMultipleValues() { - return _acceptsMultipleValues; + return _acceptsMultipleValues; } inline void Arg::reset() { - _xorSet = false; - _alreadySet = false; + _xorSet = false; + _alreadySet = false; } ////////////////////////////////////////////////////////////////////// diff --git a/src/tclap/ArgException.h b/src/tclap/ArgException.h index e9f2059..b58368e 100644 --- a/src/tclap/ArgException.h +++ b/src/tclap/ArgException.h @@ -27,7 +27,8 @@ #include #include -namespace TCLAP { +namespace TCLAP +{ /** * A simple class that defines and argument exception. Should be caught @@ -35,82 +36,85 @@ namespace TCLAP { */ class ArgException : public std::exception { - public: + public: - /** - * Constructor. - * \param text - The text of the exception. - * \param id - The text identifying the argument source. - * \param td - Text describing the type of ArgException it is. - * of the exception. - */ - ArgException( const std::string& text = "undefined exception", - const std::string& id = "undefined", - const std::string& td = "Generic ArgException") - : std::exception(), - _errorText(text), - _argId( id ), - _typeDescription(td) - { } + /** + * Constructor. + * \param text - The text of the exception. + * \param id - The text identifying the argument source. + * \param td - Text describing the type of ArgException it is. + * of the exception. + */ + ArgException( const std::string& text = "undefined exception", + const std::string& id = "undefined", + const std::string& td = "Generic ArgException") + : std::exception(), + _errorText(text), + _argId( id ), + _typeDescription(td) + { } - /** - * Destructor. - */ - virtual ~ArgException() throw() { } + /** + * Destructor. + */ + virtual ~ArgException() throw() { } - /** - * Returns the error text. - */ - std::string error() const { return ( _errorText ); } + /** + * Returns the error text. + */ + std::string error() const + { + return ( _errorText ); + } - /** - * Returns the argument id. - */ - std::string argId() const - { - if ( _argId == "undefined" ) - return " "; - else - return ( "Argument: " + _argId ); - } + /** + * Returns the argument id. + */ + std::string argId() const + { + if ( _argId == "undefined" ) + return " "; + else + return ( "Argument: " + _argId ); + } - /** - * Returns the arg id and error text. - */ - const char* what() const throw() - { - static std::string ex; - ex = _argId + " -- " + _errorText; - return ex.c_str(); - } + /** + * Returns the arg id and error text. + */ + const char* what() const throw() + { + static std::string ex; + ex = _argId + " -- " + _errorText; + return ex.c_str(); + } - /** - * Returns the type of the exception. Used to explain and distinguish - * between different child exceptions. - */ - std::string typeDescription() const - { - return _typeDescription; - } + /** + * Returns the type of the exception. Used to explain and distinguish + * between different child exceptions. + */ + std::string typeDescription() const + { + return _typeDescription; + } - private: + private: - /** - * The text of the exception message. - */ - std::string _errorText; + /** + * The text of the exception message. + */ + std::string _errorText; - /** - * The argument related to this exception. - */ - std::string _argId; + /** + * The argument related to this exception. + */ + std::string _argId; - /** - * Describes the type of the exception. Used to distinguish - * between different child exceptions. - */ - std::string _typeDescription; + /** + * Describes the type of the exception. Used to distinguish + * between different child exceptions. + */ + std::string _typeDescription; }; @@ -120,20 +124,20 @@ class ArgException : public std::exception */ class ArgParseException : public ArgException { - public: - /** - * Constructor. - * \param text - The text of the exception. - * \param id - The text identifying the argument source - * of the exception. - */ - ArgParseException( const std::string& text = "undefined exception", - const std::string& id = "undefined" ) - : ArgException( text, - id, - std::string( "Exception found while parsing " ) + - std::string( "the value the Arg has been passed." )) - { } + public: + /** + * Constructor. + * \param text - The text of the exception. + * \param id - The text identifying the argument source + * of the exception. + */ + ArgParseException( const std::string& text = "undefined exception", + const std::string& id = "undefined" ) + : ArgException( text, + id, + std::string( "Exception found while parsing " ) + + std::string( "the value the Arg has been passed." )) + { } }; /** @@ -142,22 +146,22 @@ class ArgParseException : public ArgException */ class CmdLineParseException : public ArgException { - public: - /** - * Constructor. - * \param text - The text of the exception. - * \param id - The text identifying the argument source - * of the exception. - */ - CmdLineParseException( const std::string& text = "undefined exception", - const std::string& id = "undefined" ) - : ArgException( text, - id, - std::string( "Exception found when the values ") + - std::string( "on the command line do not meet ") + - std::string( "the requirements of the defined ") + - std::string( "Args." )) - { } + public: + /** + * Constructor. + * \param text - The text of the exception. + * \param id - The text identifying the argument source + * of the exception. + */ + CmdLineParseException( const std::string& text = "undefined exception", + const std::string& id = "undefined" ) + : ArgException( text, + id, + std::string( "Exception found when the values ") + + std::string( "on the command line do not meet ") + + std::string( "the requirements of the defined ") + + std::string( "Args." )) + { } }; /** @@ -166,32 +170,36 @@ class CmdLineParseException : public ArgException */ class SpecificationException : public ArgException { - public: - /** - * Constructor. - * \param text - The text of the exception. - * \param id - The text identifying the argument source - * of the exception. - */ - SpecificationException( const std::string& text = "undefined exception", - const std::string& id = "undefined" ) - : ArgException( text, - id, - std::string("Exception found when an Arg object ")+ - std::string("is improperly defined by the ") + - std::string("developer." )) - { } + public: + /** + * Constructor. + * \param text - The text of the exception. + * \param id - The text identifying the argument source + * of the exception. + */ + SpecificationException( const std::string& text = "undefined exception", + const std::string& id = "undefined" ) + : ArgException( text, + id, + std::string("Exception found when an Arg object ")+ + std::string("is improperly defined by the ") + + std::string("developer." )) + { } }; -class ExitException { -public: - ExitException(int estat) : _estat(estat) {} +class ExitException +{ + public: + ExitException(int estat) : _estat(estat) {} - int getExitStatus() const { return _estat; } + int getExitStatus() const + { + return _estat; + } -private: - int _estat; + private: + int _estat; }; } // namespace TCLAP diff --git a/src/tclap/ArgTraits.h b/src/tclap/ArgTraits.h index 0b2c18f..adbf0d5 100644 --- a/src/tclap/ArgTraits.h +++ b/src/tclap/ArgTraits.h @@ -26,7 +26,8 @@ #ifndef TCLAP_ARGTRAITS_H #define TCLAP_ARGTRAITS_H -namespace TCLAP { +namespace TCLAP +{ // We use two empty structs to get compile type specialization // function to work @@ -35,9 +36,10 @@ namespace TCLAP { * A value like argument value type is a value that can be set using * operator>>. This is the default value type. */ -struct ValueLike { - typedef ValueLike ValueCategory; - virtual ~ValueLike() {} +struct ValueLike +{ + typedef ValueLike ValueCategory; + virtual ~ValueLike() {} }; /** @@ -45,8 +47,9 @@ struct ValueLike { * operator=(string). Usefull if the value type contains spaces which * will be broken up into individual tokens by operator>>. */ -struct StringLike { - virtual ~StringLike() {} +struct StringLike +{ + virtual ~StringLike() {} }; /** @@ -54,9 +57,10 @@ struct StringLike { * traits. This is a compile time thing and does not add any overhead * to the inherenting class. */ -struct StringLikeTrait { - typedef StringLike ValueCategory; - virtual ~StringLikeTrait() {} +struct StringLikeTrait +{ + typedef StringLike ValueCategory; + virtual ~StringLikeTrait() {} }; /** @@ -64,9 +68,10 @@ struct StringLikeTrait { * traits. This is a compile time thing and does not add any overhead * to the inherenting class. */ -struct ValueLikeTrait { - typedef ValueLike ValueCategory; - virtual ~ValueLikeTrait() {} +struct ValueLikeTrait +{ + typedef ValueLike ValueCategory; + virtual ~ValueLikeTrait() {} }; /** @@ -76,10 +81,11 @@ struct ValueLikeTrait { * supported types are StringLike and ValueLike. */ template -struct ArgTraits { - typedef typename T::ValueCategory ValueCategory; - virtual ~ArgTraits() {} - //typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef typename T::ValueCategory ValueCategory; + virtual ~ArgTraits() {} + //typedef ValueLike ValueCategory; }; #endif diff --git a/src/tclap/CmdLine.h b/src/tclap/CmdLine.h index 7d7c14b..353cfee 100644 --- a/src/tclap/CmdLine.h +++ b/src/tclap/CmdLine.h @@ -48,18 +48,19 @@ #include #include // Needed for exit(), which isn't defined in some envs. -namespace TCLAP { +namespace TCLAP +{ template void DelPtr(T ptr) { - delete ptr; + delete ptr; } template void ClearContainer(C &c) { - typedef typename C::value_type value_type; - std::for_each(c.begin(), c.end(), DelPtr); - c.clear(); + typedef typename C::value_type value_type; + std::for_each(c.begin(), c.end(), DelPtr); + c.clear(); } @@ -69,249 +70,249 @@ template void ClearContainer(C &c) */ class CmdLine : public CmdLineInterface { - protected: + protected: - /** - * The list of arguments that will be tested against the - * command line. - */ - std::list _argList; + /** + * The list of arguments that will be tested against the + * command line. + */ + std::list _argList; - /** - * The name of the program. Set to argv[0]. - */ - std::string _progName; + /** + * The name of the program. Set to argv[0]. + */ + std::string _progName; - /** - * A message used to describe the program. Used in the usage output. - */ - std::string _message; + /** + * A message used to describe the program. Used in the usage output. + */ + std::string _message; - /** - * The version to be displayed with the --version switch. - */ - std::string _version; + /** + * The version to be displayed with the --version switch. + */ + std::string _version; - /** - * The number of arguments that are required to be present on - * the command line. This is set dynamically, based on the - * Args added to the CmdLine object. - */ - int _numRequired; + /** + * The number of arguments that are required to be present on + * the command line. This is set dynamically, based on the + * Args added to the CmdLine object. + */ + int _numRequired; - /** - * The character that is used to separate the argument flag/name - * from the value. Defaults to ' ' (space). - */ - char _delimiter; + /** + * The character that is used to separate the argument flag/name + * from the value. Defaults to ' ' (space). + */ + char _delimiter; - /** - * The handler that manages xoring lists of args. - */ - XorHandler _xorHandler; + /** + * The handler that manages xoring lists of args. + */ + XorHandler _xorHandler; - /** - * A list of Args to be explicitly deleted when the destructor - * is called. At the moment, this only includes the three default - * Args. - */ - std::list _argDeleteOnExitList; + /** + * A list of Args to be explicitly deleted when the destructor + * is called. At the moment, this only includes the three default + * Args. + */ + std::list _argDeleteOnExitList; - /** - * A list of Visitors to be explicitly deleted when the destructor - * is called. At the moment, these are the Vistors created for the - * default Args. - */ - std::list _visitorDeleteOnExitList; + /** + * A list of Visitors to be explicitly deleted when the destructor + * is called. At the moment, these are the Vistors created for the + * default Args. + */ + std::list _visitorDeleteOnExitList; - /** - * Object that handles all output for the CmdLine. - */ - CmdLineOutput* _output; + /** + * Object that handles all output for the CmdLine. + */ + CmdLineOutput* _output; - /** - * Should CmdLine handle parsing exceptions internally? - */ - bool _handleExceptions; + /** + * Should CmdLine handle parsing exceptions internally? + */ + bool _handleExceptions; - /** - * Throws an exception listing the missing args. - */ - void missingArgsException(); + /** + * Throws an exception listing the missing args. + */ + void missingArgsException(); - /** - * Checks whether a name/flag string matches entirely matches - * the Arg::blankChar. Used when multiple switches are combined - * into a single argument. - * \param s - The message to be used in the usage. - */ - bool _emptyCombined(const std::string& s); + /** + * Checks whether a name/flag string matches entirely matches + * the Arg::blankChar. Used when multiple switches are combined + * into a single argument. + * \param s - The message to be used in the usage. + */ + bool _emptyCombined(const std::string& s); - /** - * Perform a delete ptr; operation on ptr when this object is deleted. - */ - void deleteOnExit(Arg* ptr); + /** + * Perform a delete ptr; operation on ptr when this object is deleted. + */ + void deleteOnExit(Arg* ptr); - /** - * Perform a delete ptr; operation on ptr when this object is deleted. - */ - void deleteOnExit(Visitor* ptr); + /** + * Perform a delete ptr; operation on ptr when this object is deleted. + */ + void deleteOnExit(Visitor* ptr); -private: + private: - /** - * Prevent accidental copying. - */ - CmdLine(const CmdLine& rhs); - CmdLine& operator=(const CmdLine& rhs); + /** + * Prevent accidental copying. + */ + CmdLine(const CmdLine& rhs); + CmdLine& operator=(const CmdLine& rhs); - /** - * Encapsulates the code common to the constructors - * (which is all of it). - */ - void _constructor(); + /** + * Encapsulates the code common to the constructors + * (which is all of it). + */ + void _constructor(); - /** - * Is set to true when a user sets the output object. We use this so - * that we don't delete objects that are created outside of this lib. - */ - bool _userSetOutput; + /** + * Is set to true when a user sets the output object. We use this so + * that we don't delete objects that are created outside of this lib. + */ + bool _userSetOutput; - /** - * Whether or not to automatically create help and version switches. - */ - bool _helpAndVersion; + /** + * Whether or not to automatically create help and version switches. + */ + bool _helpAndVersion; - public: + public: - /** - * Command line constructor. Defines how the arguments will be - * parsed. - * \param message - The message to be used in the usage - * output. - * \param delimiter - The character that is used to separate - * the argument flag/name from the value. Defaults to ' ' (space). - * \param version - The version number to be used in the - * --version switch. - * \param helpAndVersion - Whether or not to create the Help and - * Version switches. Defaults to true. - */ - CmdLine(const std::string& message, - const char delimiter = ' ', - const std::string& version = "none", - bool helpAndVersion = true); + /** + * Command line constructor. Defines how the arguments will be + * parsed. + * \param message - The message to be used in the usage + * output. + * \param delimiter - The character that is used to separate + * the argument flag/name from the value. Defaults to ' ' (space). + * \param version - The version number to be used in the + * --version switch. + * \param helpAndVersion - Whether or not to create the Help and + * Version switches. Defaults to true. + */ + CmdLine(const std::string& message, + const char delimiter = ' ', + const std::string& version = "none", + bool helpAndVersion = true); - /** - * Deletes any resources allocated by a CmdLine object. - */ - virtual ~CmdLine(); + /** + * Deletes any resources allocated by a CmdLine object. + */ + virtual ~CmdLine(); - /** - * Adds an argument to the list of arguments to be parsed. - * \param a - Argument to be added. - */ - void add( Arg& a ); + /** + * Adds an argument to the list of arguments to be parsed. + * \param a - Argument to be added. + */ + void add( Arg& a ); - /** - * An alternative add. Functionally identical. - * \param a - Argument to be added. - */ - void add( Arg* a ); + /** + * An alternative add. Functionally identical. + * \param a - Argument to be added. + */ + void add( Arg* a ); - /** - * Add two Args that will be xor'd. If this method is used, add does - * not need to be called. - * \param a - Argument to be added and xor'd. - * \param b - Argument to be added and xor'd. - */ - void xorAdd( Arg& a, Arg& b ); + /** + * Add two Args that will be xor'd. If this method is used, add does + * not need to be called. + * \param a - Argument to be added and xor'd. + * \param b - Argument to be added and xor'd. + */ + void xorAdd( Arg& a, Arg& b ); - /** - * Add a list of Args that will be xor'd. If this method is used, - * add does not need to be called. - * \param xors - List of Args to be added and xor'd. - */ - void xorAdd( std::vector& xors ); + /** + * Add a list of Args that will be xor'd. If this method is used, + * add does not need to be called. + * \param xors - List of Args to be added and xor'd. + */ + void xorAdd( std::vector& xors ); - /** - * Parses the command line. - * \param argc - Number of arguments. - * \param argv - Array of arguments. - */ - void parse(int argc, const char * const * argv); + /** + * Parses the command line. + * \param argc - Number of arguments. + * \param argv - Array of arguments. + */ + void parse(int argc, const char * const * argv); - /** - * Parses the command line. - * \param args - A vector of strings representing the args. - * args[0] is still the program name. - */ - void parse(std::vector& args); + /** + * Parses the command line. + * \param args - A vector of strings representing the args. + * args[0] is still the program name. + */ + void parse(std::vector& args); - /** - * - */ - CmdLineOutput* getOutput(); + /** + * + */ + CmdLineOutput* getOutput(); - /** - * - */ - void setOutput(CmdLineOutput* co); + /** + * + */ + void setOutput(CmdLineOutput* co); - /** - * - */ - std::string& getVersion(); + /** + * + */ + std::string& getVersion(); - /** - * - */ - std::string& getProgramName(); + /** + * + */ + std::string& getProgramName(); - /** - * - */ - std::list& getArgList(); + /** + * + */ + std::list& getArgList(); - /** - * - */ - XorHandler& getXorHandler(); + /** + * + */ + XorHandler& getXorHandler(); - /** - * - */ - char getDelimiter(); + /** + * + */ + char getDelimiter(); - /** - * - */ - std::string& getMessage(); + /** + * + */ + std::string& getMessage(); - /** - * - */ - bool hasHelpAndVersion(); + /** + * + */ + bool hasHelpAndVersion(); - /** - * Disables or enables CmdLine's internal parsing exception handling. - * - * @param state Should CmdLine handle parsing exceptions internally? - */ - void setExceptionHandling(const bool state); + /** + * Disables or enables CmdLine's internal parsing exception handling. + * + * @param state Should CmdLine handle parsing exceptions internally? + */ + void setExceptionHandling(const bool state); - /** - * Returns the current state of the internal exception handling. - * - * @retval true Parsing exceptions are handled internally. - * @retval false Parsing exceptions are propagated to the caller. - */ - bool getExceptionHandling() const; + /** + * Returns the current state of the internal exception handling. + * + * @retval true Parsing exceptions are handled internally. + * @retval false Parsing exceptions are propagated to the caller. + */ + bool getExceptionHandling() const; - /** - * Allows the CmdLine object to be reused. - */ - void reset(); + /** + * Allows the CmdLine object to be reused. + */ + void reset(); }; @@ -324,7 +325,7 @@ inline CmdLine::CmdLine(const std::string& m, char delim, const std::string& v, bool help ) - : + : _argList(std::list()), _progName("not_set_yet"), _message(m), @@ -339,288 +340,272 @@ inline CmdLine::CmdLine(const std::string& m, _userSetOutput(false), _helpAndVersion(help) { - _constructor(); + _constructor(); } inline CmdLine::~CmdLine() { - ClearContainer(_argDeleteOnExitList); - ClearContainer(_visitorDeleteOnExitList); - - if ( !_userSetOutput ) { - delete _output; - _output = 0; - } + ClearContainer(_argDeleteOnExitList); + ClearContainer(_visitorDeleteOnExitList); + if ( !_userSetOutput ) + { + delete _output; + _output = 0; + } } inline void CmdLine::_constructor() { - _output = new StdOutput; - - Arg::setDelimiter( _delimiter ); - - Visitor* v; - - if ( _helpAndVersion ) - { - v = new HelpVisitor( this, &_output ); - SwitchArg* help = new SwitchArg("h","help", - "Displays usage information and exits.", - false, v); - add( help ); - deleteOnExit(help); - deleteOnExit(v); - - v = new VersionVisitor( this, &_output ); - SwitchArg* vers = new SwitchArg("","version", - "Displays version information and exits.", - false, v); - add( vers ); - deleteOnExit(vers); - deleteOnExit(v); - } - - v = new IgnoreRestVisitor(); - SwitchArg* ignore = new SwitchArg(Arg::flagStartString(), - Arg::ignoreNameString(), - "Ignores the rest of the labeled arguments following this flag.", - false, v); - add( ignore ); - deleteOnExit(ignore); - deleteOnExit(v); + _output = new StdOutput; + Arg::setDelimiter( _delimiter ); + Visitor* v; + if ( _helpAndVersion ) + { + v = new HelpVisitor( this, &_output ); + SwitchArg* help = new SwitchArg("h","help", + "Displays usage information and exits.", + false, v); + add( help ); + deleteOnExit(help); + deleteOnExit(v); + v = new VersionVisitor( this, &_output ); + SwitchArg* vers = new SwitchArg("","version", + "Displays version information and exits.", + false, v); + add( vers ); + deleteOnExit(vers); + deleteOnExit(v); + } + v = new IgnoreRestVisitor(); + SwitchArg* ignore = new SwitchArg(Arg::flagStartString(), + Arg::ignoreNameString(), + "Ignores the rest of the labeled arguments following this flag.", + false, v); + add( ignore ); + deleteOnExit(ignore); + deleteOnExit(v); } inline void CmdLine::xorAdd( std::vector& ors ) { - _xorHandler.add( ors ); - - for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++) - { - (*it)->forceRequired(); - (*it)->setRequireLabel( "OR required" ); - add( *it ); - } + _xorHandler.add( ors ); + for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++) + { + (*it)->forceRequired(); + (*it)->setRequireLabel( "OR required" ); + add( *it ); + } } inline void CmdLine::xorAdd( Arg& a, Arg& b ) { - std::vector ors; - ors.push_back( &a ); - ors.push_back( &b ); - xorAdd( ors ); + std::vector ors; + ors.push_back( &a ); + ors.push_back( &b ); + xorAdd( ors ); } inline void CmdLine::add( Arg& a ) { - add( &a ); + add( &a ); } inline void CmdLine::add( Arg* a ) { - for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ ) - if ( *a == *(*it) ) - throw( SpecificationException( - "Argument with same flag/name already exists!", - a->longID() ) ); - - a->addToList( _argList ); - - if ( a->isRequired() ) - _numRequired++; + for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ ) + if ( *a == *(*it) ) + throw( SpecificationException( + "Argument with same flag/name already exists!", + a->longID() ) ); + a->addToList( _argList ); + if ( a->isRequired() ) + _numRequired++; } inline void CmdLine::parse(int argc, const char * const * argv) { - // this step is necessary so that we have easy access to - // mutable strings. - std::vector args; - for (int i = 0; i < argc; i++) - args.push_back(argv[i]); - - parse(args); + // this step is necessary so that we have easy access to + // mutable strings. + std::vector args; + for (int i = 0; i < argc; i++) + args.push_back(argv[i]); + parse(args); } inline void CmdLine::parse(std::vector& args) { - bool shouldExit = false; - int estat = 0; - - try { - _progName = args.front(); - args.erase(args.begin()); - - int requiredCount = 0; - - for (int i = 0; static_cast(i) < args.size(); i++) - { - bool matched = false; - for (ArgListIterator it = _argList.begin(); - it != _argList.end(); it++) { - if ( (*it)->processArg( &i, args ) ) - { - requiredCount += _xorHandler.check( *it ); - matched = true; - break; - } - } - - // checks to see if the argument is an empty combined - // switch and if so, then we've actually matched it - if ( !matched && _emptyCombined( args[i] ) ) - matched = true; - - if ( !matched && !Arg::ignoreRest() ) - throw(CmdLineParseException("Couldn't find match " - "for argument", - args[i])); - } - - if ( requiredCount < _numRequired ) - missingArgsException(); - - if ( requiredCount > _numRequired ) - throw(CmdLineParseException("Too many arguments!")); - - } catch ( ArgException& e ) { - // If we're not handling the exceptions, rethrow. - if ( !_handleExceptions) { - throw; - } - - try { - _output->failure(*this,e); - } catch ( ExitException &ee ) { - estat = ee.getExitStatus(); - shouldExit = true; - } - } catch (ExitException &ee) { - // If we're not handling the exceptions, rethrow. - if ( !_handleExceptions) { - throw; - } - - estat = ee.getExitStatus(); - shouldExit = true; - } - - if (shouldExit) - exit(estat); + bool shouldExit = false; + int estat = 0; + try + { + _progName = args.front(); + args.erase(args.begin()); + int requiredCount = 0; + for (int i = 0; static_cast(i) < args.size(); i++) + { + bool matched = false; + for (ArgListIterator it = _argList.begin(); + it != _argList.end(); it++) + { + if ( (*it)->processArg( &i, args ) ) + { + requiredCount += _xorHandler.check( *it ); + matched = true; + break; + } + } + // checks to see if the argument is an empty combined + // switch and if so, then we've actually matched it + if ( !matched && _emptyCombined( args[i] ) ) + matched = true; + if ( !matched && !Arg::ignoreRest() ) + throw(CmdLineParseException("Couldn't find match " + "for argument", + args[i])); + } + if ( requiredCount < _numRequired ) + missingArgsException(); + if ( requiredCount > _numRequired ) + throw(CmdLineParseException("Too many arguments!")); + } + catch ( ArgException& e ) + { + // If we're not handling the exceptions, rethrow. + if ( !_handleExceptions) + { + throw; + } + try + { + _output->failure(*this,e); + } + catch ( ExitException &ee ) + { + estat = ee.getExitStatus(); + shouldExit = true; + } + } + catch (ExitException &ee) + { + // If we're not handling the exceptions, rethrow. + if ( !_handleExceptions) + { + throw; + } + estat = ee.getExitStatus(); + shouldExit = true; + } + if (shouldExit) + exit(estat); } inline bool CmdLine::_emptyCombined(const std::string& s) { - if ( s.length() > 0 && s[0] != Arg::flagStartChar() ) - return false; - - for ( int i = 1; static_cast(i) < s.length(); i++ ) - if ( s[i] != Arg::blankChar() ) - return false; - - return true; + if ( s.length() > 0 && s[0] != Arg::flagStartChar() ) + return false; + for ( int i = 1; static_cast(i) < s.length(); i++ ) + if ( s[i] != Arg::blankChar() ) + return false; + return true; } inline void CmdLine::missingArgsException() { - int count = 0; - - std::string missingArgList; - for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++) - { - if ( (*it)->isRequired() && !(*it)->isSet() ) - { - missingArgList += (*it)->getName(); - missingArgList += ", "; - count++; - } - } - missingArgList = missingArgList.substr(0,missingArgList.length()-2); - - std::string msg; - if ( count > 1 ) - msg = "Required arguments missing: "; - else - msg = "Required argument missing: "; - - msg += missingArgList; - - throw(CmdLineParseException(msg)); + int count = 0; + std::string missingArgList; + for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++) + { + if ( (*it)->isRequired() && !(*it)->isSet() ) + { + missingArgList += (*it)->getName(); + missingArgList += ", "; + count++; + } + } + missingArgList = missingArgList.substr(0,missingArgList.length()-2); + std::string msg; + if ( count > 1 ) + msg = "Required arguments missing: "; + else + msg = "Required argument missing: "; + msg += missingArgList; + throw(CmdLineParseException(msg)); } inline void CmdLine::deleteOnExit(Arg* ptr) { - _argDeleteOnExitList.push_back(ptr); + _argDeleteOnExitList.push_back(ptr); } inline void CmdLine::deleteOnExit(Visitor* ptr) { - _visitorDeleteOnExitList.push_back(ptr); + _visitorDeleteOnExitList.push_back(ptr); } inline CmdLineOutput* CmdLine::getOutput() { - return _output; + return _output; } inline void CmdLine::setOutput(CmdLineOutput* co) { - if ( !_userSetOutput ) - delete _output; - _userSetOutput = true; - _output = co; + if ( !_userSetOutput ) + delete _output; + _userSetOutput = true; + _output = co; } inline std::string& CmdLine::getVersion() { - return _version; + return _version; } inline std::string& CmdLine::getProgramName() { - return _progName; + return _progName; } inline std::list& CmdLine::getArgList() { - return _argList; + return _argList; } inline XorHandler& CmdLine::getXorHandler() { - return _xorHandler; + return _xorHandler; } inline char CmdLine::getDelimiter() { - return _delimiter; + return _delimiter; } inline std::string& CmdLine::getMessage() { - return _message; + return _message; } inline bool CmdLine::hasHelpAndVersion() { - return _helpAndVersion; + return _helpAndVersion; } inline void CmdLine::setExceptionHandling(const bool state) { - _handleExceptions = state; + _handleExceptions = state; } inline bool CmdLine::getExceptionHandling() const { - return _handleExceptions; + return _handleExceptions; } inline void CmdLine::reset() { - for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ ) - (*it)->reset(); - - _progName.clear(); + for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ ) + (*it)->reset(); + _progName.clear(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/tclap/CmdLineInterface.h b/src/tclap/CmdLineInterface.h index 7b0fd3e..86329a9 100644 --- a/src/tclap/CmdLineInterface.h +++ b/src/tclap/CmdLineInterface.h @@ -30,7 +30,8 @@ #include -namespace TCLAP { +namespace TCLAP +{ class Arg; class CmdLineOutput; @@ -42,106 +43,106 @@ class XorHandler; */ class CmdLineInterface { - public: + public: - /** - * Destructor - */ - virtual ~CmdLineInterface() {} + /** + * Destructor + */ + virtual ~CmdLineInterface() {} - /** - * Adds an argument to the list of arguments to be parsed. - * \param a - Argument to be added. - */ - virtual void add( Arg& a )=0; + /** + * Adds an argument to the list of arguments to be parsed. + * \param a - Argument to be added. + */ + virtual void add( Arg& a )=0; - /** - * An alternative add. Functionally identical. - * \param a - Argument to be added. - */ - virtual void add( Arg* a )=0; + /** + * An alternative add. Functionally identical. + * \param a - Argument to be added. + */ + virtual void add( Arg* a )=0; - /** - * Add two Args that will be xor'd. - * If this method is used, add does - * not need to be called. - * \param a - Argument to be added and xor'd. - * \param b - Argument to be added and xor'd. - */ - virtual void xorAdd( Arg& a, Arg& b )=0; + /** + * Add two Args that will be xor'd. + * If this method is used, add does + * not need to be called. + * \param a - Argument to be added and xor'd. + * \param b - Argument to be added and xor'd. + */ + virtual void xorAdd( Arg& a, Arg& b )=0; - /** - * Add a list of Args that will be xor'd. If this method is used, - * add does not need to be called. - * \param xors - List of Args to be added and xor'd. - */ - virtual void xorAdd( std::vector& xors )=0; + /** + * Add a list of Args that will be xor'd. If this method is used, + * add does not need to be called. + * \param xors - List of Args to be added and xor'd. + */ + virtual void xorAdd( std::vector& xors )=0; - /** - * Parses the command line. - * \param argc - Number of arguments. - * \param argv - Array of arguments. - */ - virtual void parse(int argc, const char * const * argv)=0; + /** + * Parses the command line. + * \param argc - Number of arguments. + * \param argv - Array of arguments. + */ + virtual void parse(int argc, const char * const * argv)=0; - /** - * Parses the command line. - * \param args - A vector of strings representing the args. - * args[0] is still the program name. - */ - void parse(std::vector& args); + /** + * Parses the command line. + * \param args - A vector of strings representing the args. + * args[0] is still the program name. + */ + void parse(std::vector& args); - /** - * Returns the CmdLineOutput object. - */ - virtual CmdLineOutput* getOutput()=0; + /** + * Returns the CmdLineOutput object. + */ + virtual CmdLineOutput* getOutput()=0; - /** - * \param co - CmdLineOutput object that we want to use instead. - */ - virtual void setOutput(CmdLineOutput* co)=0; + /** + * \param co - CmdLineOutput object that we want to use instead. + */ + virtual void setOutput(CmdLineOutput* co)=0; - /** - * Returns the version string. - */ - virtual std::string& getVersion()=0; + /** + * Returns the version string. + */ + virtual std::string& getVersion()=0; - /** - * Returns the program name string. - */ - virtual std::string& getProgramName()=0; + /** + * Returns the program name string. + */ + virtual std::string& getProgramName()=0; - /** - * Returns the argList. - */ - virtual std::list& getArgList()=0; + /** + * Returns the argList. + */ + virtual std::list& getArgList()=0; - /** - * Returns the XorHandler. - */ - virtual XorHandler& getXorHandler()=0; + /** + * Returns the XorHandler. + */ + virtual XorHandler& getXorHandler()=0; - /** - * Returns the delimiter string. - */ - virtual char getDelimiter()=0; + /** + * Returns the delimiter string. + */ + virtual char getDelimiter()=0; - /** - * Returns the message string. - */ - virtual std::string& getMessage()=0; + /** + * Returns the message string. + */ + virtual std::string& getMessage()=0; - /** - * Indicates whether or not the help and version switches were created - * automatically. - */ - virtual bool hasHelpAndVersion()=0; + /** + * Indicates whether or not the help and version switches were created + * automatically. + */ + virtual bool hasHelpAndVersion()=0; - /** - * Resets the instance as if it had just been constructed so that the - * instance can be reused. - */ - virtual void reset()=0; + /** + * Resets the instance as if it had just been constructed so that the + * instance can be reused. + */ + virtual void reset()=0; }; } //namespace diff --git a/src/tclap/CmdLineOutput.h b/src/tclap/CmdLineOutput.h index 993b1d9..539d3f3 100644 --- a/src/tclap/CmdLineOutput.h +++ b/src/tclap/CmdLineOutput.h @@ -30,7 +30,8 @@ #include #include -namespace TCLAP { +namespace TCLAP +{ class CmdLineInterface; class ArgException; @@ -41,32 +42,32 @@ class ArgException; class CmdLineOutput { - public: + public: - /** - * Virtual destructor. - */ - virtual ~CmdLineOutput() {} + /** + * Virtual destructor. + */ + virtual ~CmdLineOutput() {} - /** - * Generates some sort of output for the USAGE. - * \param c - The CmdLine object the output is generated for. - */ - virtual void usage(CmdLineInterface& c)=0; + /** + * Generates some sort of output for the USAGE. + * \param c - The CmdLine object the output is generated for. + */ + virtual void usage(CmdLineInterface& c)=0; - /** - * Generates some sort of output for the version. - * \param c - The CmdLine object the output is generated for. - */ - virtual void version(CmdLineInterface& c)=0; + /** + * Generates some sort of output for the version. + * \param c - The CmdLine object the output is generated for. + */ + virtual void version(CmdLineInterface& c)=0; - /** - * Generates some sort of output for a failure. - * \param c - The CmdLine object the output is generated for. - * \param e - The ArgException that caused the failure. - */ - virtual void failure( CmdLineInterface& c, - ArgException& e )=0; + /** + * Generates some sort of output for a failure. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. + */ + virtual void failure( CmdLineInterface& c, + ArgException& e )=0; }; diff --git a/src/tclap/Constraint.h b/src/tclap/Constraint.h index a92acf9..7930010 100644 --- a/src/tclap/Constraint.h +++ b/src/tclap/Constraint.h @@ -29,7 +29,8 @@ #include #include -namespace TCLAP { +namespace TCLAP +{ /** * The interface that defines the interaction between the Arg and Constraint. @@ -38,30 +39,33 @@ template class Constraint { - public: - /** - * Returns a description of the Constraint. - */ - virtual std::string description() const =0; + public: + /** + * Returns a description of the Constraint. + */ + virtual std::string description() const =0; - /** - * Returns the short ID for the Constraint. - */ - virtual std::string shortID() const =0; + /** + * Returns the short ID for the Constraint. + */ + virtual std::string shortID() const =0; - /** - * The method used to verify that the value parsed from the command - * line meets the constraint. - * \param value - The value that will be checked. - */ - virtual bool check(const T& value) const =0; + /** + * The method used to verify that the value parsed from the command + * line meets the constraint. + * \param value - The value that will be checked. + */ + virtual bool check(const T& value) const =0; - /** - * Destructor. - * Silences warnings about Constraint being a base class with virtual - * functions but without a virtual destructor. - */ - virtual ~Constraint() { ; } + /** + * Destructor. + * Silences warnings about Constraint being a base class with virtual + * functions but without a virtual destructor. + */ + virtual ~Constraint() + { + ; + } }; } //namespace TCLAP diff --git a/src/tclap/DocBookOutput.h b/src/tclap/DocBookOutput.h index 00ccc75..7c1930b 100644 --- a/src/tclap/DocBookOutput.h +++ b/src/tclap/DocBookOutput.h @@ -34,7 +34,8 @@ #include #include -namespace TCLAP { +namespace TCLAP +{ /** * A class that generates DocBook output for usage() method for the @@ -43,256 +44,226 @@ namespace TCLAP { class DocBookOutput : public CmdLineOutput { - public: + public: - /** - * Prints the usage to stdout. Can be overridden to - * produce alternative behavior. - * \param c - The CmdLine object the output is generated for. - */ - virtual void usage(CmdLineInterface& c); + /** + * Prints the usage to stdout. Can be overridden to + * produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void usage(CmdLineInterface& c); - /** - * Prints the version to stdout. Can be overridden - * to produce alternative behavior. - * \param c - The CmdLine object the output is generated for. - */ - virtual void version(CmdLineInterface& c); + /** + * Prints the version to stdout. Can be overridden + * to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void version(CmdLineInterface& c); - /** - * Prints (to stderr) an error message, short usage - * Can be overridden to produce alternative behavior. - * \param c - The CmdLine object the output is generated for. - * \param e - The ArgException that caused the failure. - */ - virtual void failure(CmdLineInterface& c, - ArgException& e ); + /** + * Prints (to stderr) an error message, short usage + * Can be overridden to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. + */ + virtual void failure(CmdLineInterface& c, + ArgException& e ); - protected: + protected: - /** - * Substitutes the char r for string x in string s. - * \param s - The string to operate on. - * \param r - The char to replace. - * \param x - What to replace r with. - */ - void substituteSpecialChars( std::string& s, char r, std::string& x ); - void removeChar( std::string& s, char r); - void basename( std::string& s ); + /** + * Substitutes the char r for string x in string s. + * \param s - The string to operate on. + * \param r - The char to replace. + * \param x - What to replace r with. + */ + void substituteSpecialChars( std::string& s, char r, std::string& x ); + void removeChar( std::string& s, char r); + void basename( std::string& s ); - void printShortArg(Arg* it); - void printLongArg(Arg* it); + void printShortArg(Arg* it); + void printLongArg(Arg* it); - char theDelimiter; + char theDelimiter; }; inline void DocBookOutput::version(CmdLineInterface& _cmd) { - std::cout << _cmd.getVersion() << std::endl; + std::cout << _cmd.getVersion() << std::endl; } inline void DocBookOutput::usage(CmdLineInterface& _cmd ) { - std::list argList = _cmd.getArgList(); - std::string progName = _cmd.getProgramName(); - std::string xversion = _cmd.getVersion(); - theDelimiter = _cmd.getDelimiter(); - XorHandler xorHandler = _cmd.getXorHandler(); - std::vector< std::vector > xorList = xorHandler.getXorList(); - basename(progName); - - std::cout << "" << std::endl; - std::cout << "" << std::endl << std::endl; - - std::cout << "" << std::endl; - - std::cout << "" << std::endl; - std::cout << "" << progName << "" << std::endl; - std::cout << "1" << std::endl; - std::cout << "" << std::endl; - - std::cout << "" << std::endl; - std::cout << "" << progName << "" << std::endl; - std::cout << "" << _cmd.getMessage() << "" << std::endl; - std::cout << "" << std::endl; - - std::cout << "" << std::endl; - std::cout << "" << std::endl; - - std::cout << "" << progName << "" << std::endl; - - // xor - for ( int i = 0; (unsigned int)i < xorList.size(); i++ ) - { - std::cout << "" << std::endl; - for ( ArgVectorIterator it = xorList[i].begin(); - it != xorList[i].end(); it++ ) - printShortArg((*it)); - - std::cout << "" << std::endl; - } - - // rest of args - for (ArgListIterator it = argList.begin(); it != argList.end(); it++) - if ( !xorHandler.contains( (*it) ) ) - printShortArg((*it)); - - std::cout << "" << std::endl; - std::cout << "" << std::endl; - - std::cout << "" << std::endl; - std::cout << "Description" << std::endl; - std::cout << "" << std::endl; - std::cout << _cmd.getMessage() << std::endl; - std::cout << "" << std::endl; - std::cout << "" << std::endl; - - std::cout << "" << std::endl; - std::cout << "Options" << std::endl; - - std::cout << "" << std::endl; - - for (ArgListIterator it = argList.begin(); it != argList.end(); it++) - printLongArg((*it)); - - std::cout << "" << std::endl; - std::cout << "" << std::endl; - - std::cout << "" << std::endl; - std::cout << "Version" << std::endl; - std::cout << "" << std::endl; - std::cout << xversion << std::endl; - std::cout << "" << std::endl; - std::cout << "" << std::endl; - - std::cout << "" << std::endl; - + std::list argList = _cmd.getArgList(); + std::string progName = _cmd.getProgramName(); + std::string xversion = _cmd.getVersion(); + theDelimiter = _cmd.getDelimiter(); + XorHandler xorHandler = _cmd.getXorHandler(); + std::vector< std::vector > xorList = xorHandler.getXorList(); + basename(progName); + std::cout << "" << std::endl; + std::cout << "" << std::endl << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << progName << "" << std::endl; + std::cout << "1" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << progName << "" << std::endl; + std::cout << "" << _cmd.getMessage() << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << progName << "" << std::endl; + // xor + for ( int i = 0; (unsigned int)i < xorList.size(); i++ ) + { + std::cout << "" << std::endl; + for ( ArgVectorIterator it = xorList[i].begin(); + it != xorList[i].end(); it++ ) + printShortArg((*it)); + std::cout << "" << std::endl; + } + // rest of args + for (ArgListIterator it = argList.begin(); it != argList.end(); it++) + if ( !xorHandler.contains( (*it) ) ) + printShortArg((*it)); + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "Description" << std::endl; + std::cout << "" << std::endl; + std::cout << _cmd.getMessage() << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "Options" << std::endl; + std::cout << "" << std::endl; + for (ArgListIterator it = argList.begin(); it != argList.end(); it++) + printLongArg((*it)); + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "Version" << std::endl; + std::cout << "" << std::endl; + std::cout << xversion << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; } inline void DocBookOutput::failure( CmdLineInterface& _cmd, - ArgException& e ) + ArgException& e ) { - static_cast(_cmd); // unused - std::cout << e.what() << std::endl; - throw ExitException(1); + static_cast(_cmd); // unused + std::cout << e.what() << std::endl; + throw ExitException(1); } inline void DocBookOutput::substituteSpecialChars( std::string& s, - char r, - std::string& x ) + char r, + std::string& x ) { - size_t p; - while ( (p = s.find_first_of(r)) != std::string::npos ) - { - s.erase(p,1); - s.insert(p,x); - } + size_t p; + while ( (p = s.find_first_of(r)) != std::string::npos ) + { + s.erase(p,1); + s.insert(p,x); + } } inline void DocBookOutput::removeChar( std::string& s, char r) { - size_t p; - while ( (p = s.find_first_of(r)) != std::string::npos ) - { - s.erase(p,1); - } + size_t p; + while ( (p = s.find_first_of(r)) != std::string::npos ) + { + s.erase(p,1); + } } inline void DocBookOutput::basename( std::string& s ) { - size_t p = s.find_last_of('/'); - if ( p != std::string::npos ) - { - s.erase(0, p + 1); - } + size_t p = s.find_last_of('/'); + if ( p != std::string::npos ) + { + s.erase(0, p + 1); + } } inline void DocBookOutput::printShortArg(Arg* a) { - std::string lt = "<"; - std::string gt = ">"; - - std::string id = a->shortID(); - substituteSpecialChars(id,'<',lt); - substituteSpecialChars(id,'>',gt); - removeChar(id,'['); - removeChar(id,']'); - - std::string choice = "opt"; - if ( a->isRequired() ) - choice = "plain"; - - std::cout << "acceptsMultipleValues() ) - std::cout << " rep='repeat'"; - - - std::cout << '>'; - if ( !a->getFlag().empty() ) - std::cout << a->flagStartChar() << a->getFlag(); - else - std::cout << a->nameStartString() << a->getName(); - if ( a->isValueRequired() ) - { - std::string arg = a->shortID(); - removeChar(arg,'['); - removeChar(arg,']'); - removeChar(arg,'<'); - removeChar(arg,'>'); - arg.erase(0, arg.find_last_of(theDelimiter) + 1); - std::cout << theDelimiter; - std::cout << "" << arg << ""; - } - std::cout << "" << std::endl; - + std::string lt = "<"; + std::string gt = ">"; + std::string id = a->shortID(); + substituteSpecialChars(id,'<',lt); + substituteSpecialChars(id,'>',gt); + removeChar(id,'['); + removeChar(id,']'); + std::string choice = "opt"; + if ( a->isRequired() ) + choice = "plain"; + std::cout << "acceptsMultipleValues() ) + std::cout << " rep='repeat'"; + std::cout << '>'; + if ( !a->getFlag().empty() ) + std::cout << a->flagStartChar() << a->getFlag(); + else + std::cout << a->nameStartString() << a->getName(); + if ( a->isValueRequired() ) + { + std::string arg = a->shortID(); + removeChar(arg,'['); + removeChar(arg,']'); + removeChar(arg,'<'); + removeChar(arg,'>'); + arg.erase(0, arg.find_last_of(theDelimiter) + 1); + std::cout << theDelimiter; + std::cout << "" << arg << ""; + } + std::cout << "" << std::endl; } inline void DocBookOutput::printLongArg(Arg* a) { - std::string lt = "<"; - std::string gt = ">"; - - std::string desc = a->getDescription(); - substituteSpecialChars(desc,'<',lt); - substituteSpecialChars(desc,'>',gt); - - std::cout << "" << std::endl; - - if ( !a->getFlag().empty() ) - { - std::cout << "" << std::endl; - std::cout << "" << std::endl; - std::cout << "" << std::endl; - } - - std::cout << "" << std::endl; - std::cout << "" << std::endl; - std::cout << "" << std::endl; - - std::cout << "" << std::endl; - std::cout << "" << std::endl; - std::cout << desc << std::endl; - std::cout << "" << std::endl; - std::cout << "" << std::endl; - - std::cout << "" << std::endl; + std::string lt = "<"; + std::string gt = ">"; + std::string desc = a->getDescription(); + substituteSpecialChars(desc,'<',lt); + substituteSpecialChars(desc,'>',gt); + std::cout << "" << std::endl; + if ( !a->getFlag().empty() ) + { + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + } + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << desc << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; } } //namespace TCLAP diff --git a/src/tclap/HelpVisitor.h b/src/tclap/HelpVisitor.h index fec4b1d..33f8464 100644 --- a/src/tclap/HelpVisitor.h +++ b/src/tclap/HelpVisitor.h @@ -26,7 +26,8 @@ #include "CmdLineOutput.h" #include "Visitor.h" -namespace TCLAP { +namespace TCLAP +{ /** * A Visitor object that calls the usage method of the given CmdLineOutput @@ -34,40 +35,44 @@ namespace TCLAP { */ class HelpVisitor: public Visitor { - private: - /** - * Prevent accidental copying. - */ - HelpVisitor(const HelpVisitor& rhs); - HelpVisitor& operator=(const HelpVisitor& rhs); + private: + /** + * Prevent accidental copying. + */ + HelpVisitor(const HelpVisitor& rhs); + HelpVisitor& operator=(const HelpVisitor& rhs); - protected: + protected: - /** - * The CmdLine the output will be generated for. - */ - CmdLineInterface* _cmd; + /** + * The CmdLine the output will be generated for. + */ + CmdLineInterface* _cmd; - /** - * The output object. - */ - CmdLineOutput** _out; + /** + * The output object. + */ + CmdLineOutput** _out; - public: + public: - /** - * Constructor. - * \param cmd - The CmdLine the output will be generated for. - * \param out - The type of output. - */ - HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out) - : Visitor(), _cmd( cmd ), _out( out ) { } + /** + * Constructor. + * \param cmd - The CmdLine the output will be generated for. + * \param out - The type of output. + */ + HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out) + : Visitor(), _cmd( cmd ), _out( out ) { } - /** - * Calls the usage method of the CmdLineOutput for the - * specified CmdLine. - */ - void visit() { (*_out)->usage(*_cmd); throw ExitException(0); } + /** + * Calls the usage method of the CmdLineOutput for the + * specified CmdLine. + */ + void visit() + { + (*_out)->usage(*_cmd); + throw ExitException(0); + } }; diff --git a/src/tclap/IgnoreRestVisitor.h b/src/tclap/IgnoreRestVisitor.h index 4601013..3be2eee 100644 --- a/src/tclap/IgnoreRestVisitor.h +++ b/src/tclap/IgnoreRestVisitor.h @@ -26,7 +26,8 @@ #include "Visitor.h" #include "Arg.h" -namespace TCLAP { +namespace TCLAP +{ /** * A Vistor that tells the CmdLine to begin ignoring arguments after @@ -34,17 +35,20 @@ namespace TCLAP { */ class IgnoreRestVisitor: public Visitor { - public: + public: - /** - * Constructor. - */ - IgnoreRestVisitor() : Visitor() {} + /** + * Constructor. + */ + IgnoreRestVisitor() : Visitor() {} - /** - * Sets Arg::_ignoreRest. - */ - void visit() { Arg::beginIgnoring(); } + /** + * Sets Arg::_ignoreRest. + */ + void visit() + { + Arg::beginIgnoring(); + } }; } diff --git a/src/tclap/MultiArg.h b/src/tclap/MultiArg.h index 8c36c7f..e2e97f4 100644 --- a/src/tclap/MultiArg.h +++ b/src/tclap/MultiArg.h @@ -29,7 +29,8 @@ #include "Arg.h" #include "Constraint.h" -namespace TCLAP { +namespace TCLAP +{ /** * An argument that allows multiple values of type T to be specified. Very * similar to a ValueArg, except a vector of values will be returned @@ -38,195 +39,201 @@ namespace TCLAP { template class MultiArg : public Arg { -public: - typedef std::vector container_type; - typedef typename container_type::iterator iterator; - typedef typename container_type::const_iterator const_iterator; + public: + typedef std::vector container_type; + typedef typename container_type::iterator iterator; + typedef typename container_type::const_iterator const_iterator; -protected: + protected: - /** - * The list of values parsed from the CmdLine. - */ - std::vector _values; + /** + * The list of values parsed from the CmdLine. + */ + std::vector _values; - /** - * The description of type T to be used in the usage. - */ - std::string _typeDesc; + /** + * The description of type T to be used in the usage. + */ + std::string _typeDesc; - /** - * A list of constraint on this Arg. - */ - Constraint* _constraint; + /** + * A list of constraint on this Arg. + */ + Constraint* _constraint; - /** - * Extracts the value from the string. - * Attempts to parse string as type T, if this fails an exception - * is thrown. - * \param val - The string to be read. - */ - void _extractValue( const std::string& val ); + /** + * Extracts the value from the string. + * Attempts to parse string as type T, if this fails an exception + * is thrown. + * \param val - The string to be read. + */ + void _extractValue( const std::string& val ); - /** - * Used by XorHandler to decide whether to keep parsing for this arg. - */ - bool _allowMore; + /** + * Used by XorHandler to decide whether to keep parsing for this arg. + */ + bool _allowMore; -public: + public: - /** - * Constructor. - * \param flag - The one character flag that identifies this - * argument on the command line. - * \param name - A one word name for the argument. Can be - * used as a long flag on the command line. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param typeDesc - A short, human readable description of the - * type that this object expects. This is used in the generation - * of the USAGE statement. The goal is to be helpful to the end user - * of the program. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - MultiArg( const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, - const std::string& typeDesc, - Visitor* v = NULL); + /** + * Constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + MultiArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + const std::string& typeDesc, + Visitor* v = NULL); - /** - * Constructor. - * \param flag - The one character flag that identifies this - * argument on the command line. - * \param name - A one word name for the argument. Can be - * used as a long flag on the command line. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param typeDesc - A short, human readable description of the - * type that this object expects. This is used in the generation - * of the USAGE statement. The goal is to be helpful to the end user - * of the program. - * \param parser - A CmdLine parser object to add this Arg to - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - MultiArg( const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, - const std::string& typeDesc, - CmdLineInterface& parser, - Visitor* v = NULL ); + /** + * Constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param parser - A CmdLine parser object to add this Arg to + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + MultiArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + const std::string& typeDesc, + CmdLineInterface& parser, + Visitor* v = NULL ); - /** - * Constructor. - * \param flag - The one character flag that identifies this - * argument on the command line. - * \param name - A one word name for the argument. Can be - * used as a long flag on the command line. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param constraint - A pointer to a Constraint object used - * to constrain this Arg. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - MultiArg( const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, - Constraint* constraint, - Visitor* v = NULL ); + /** + * Constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + MultiArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + Constraint* constraint, + Visitor* v = NULL ); - /** - * Constructor. - * \param flag - The one character flag that identifies this - * argument on the command line. - * \param name - A one word name for the argument. Can be - * used as a long flag on the command line. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param constraint - A pointer to a Constraint object used - * to constrain this Arg. - * \param parser - A CmdLine parser object to add this Arg to - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - MultiArg( const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, - Constraint* constraint, - CmdLineInterface& parser, - Visitor* v = NULL ); + /** + * Constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param parser - A CmdLine parser object to add this Arg to + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + MultiArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + Constraint* constraint, + CmdLineInterface& parser, + Visitor* v = NULL ); - /** - * Handles the processing of the argument. - * This re-implements the Arg version of this method to set the - * _value of the argument appropriately. It knows the difference - * between labeled and unlabeled. - * \param i - Pointer the the current argument in the list. - * \param args - Mutable list of strings. Passed from main(). - */ - virtual bool processArg(int* i, std::vector& args); + /** + * Handles the processing of the argument. + * This re-implements the Arg version of this method to set the + * _value of the argument appropriately. It knows the difference + * between labeled and unlabeled. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. Passed from main(). + */ + virtual bool processArg(int* i, std::vector& args); - /** - * Returns a vector of type T containing the values parsed from - * the command line. - */ - const std::vector& getValue(); + /** + * Returns a vector of type T containing the values parsed from + * the command line. + */ + const std::vector& getValue(); - /** - * Returns an iterator over the values parsed from the command - * line. - */ - const_iterator begin() const { return _values.begin(); } + /** + * Returns an iterator over the values parsed from the command + * line. + */ + const_iterator begin() const + { + return _values.begin(); + } - /** - * Returns the end of the values parsed from the command - * line. - */ - const_iterator end() const { return _values.end(); } + /** + * Returns the end of the values parsed from the command + * line. + */ + const_iterator end() const + { + return _values.end(); + } - /** - * Returns the a short id string. Used in the usage. - * \param val - value to be used. - */ - virtual std::string shortID(const std::string& val="val") const; + /** + * Returns the a short id string. Used in the usage. + * \param val - value to be used. + */ + virtual std::string shortID(const std::string& val="val") const; - /** - * Returns the a long id string. Used in the usage. - * \param val - value to be used. - */ - virtual std::string longID(const std::string& val="val") const; + /** + * Returns the a long id string. Used in the usage. + * \param val - value to be used. + */ + virtual std::string longID(const std::string& val="val") const; - /** - * Once we've matched the first value, then the arg is no longer - * required. - */ - virtual bool isRequired() const; + /** + * Once we've matched the first value, then the arg is no longer + * required. + */ + virtual bool isRequired() const; - virtual bool allowMore(); + virtual bool allowMore(); - virtual void reset(); + virtual void reset(); -private: - /** - * Prevent accidental copying - */ - MultiArg(const MultiArg& rhs); - MultiArg& operator=(const MultiArg& rhs); + private: + /** + * Prevent accidental copying + */ + MultiArg(const MultiArg& rhs); + MultiArg& operator=(const MultiArg& rhs); }; @@ -237,13 +244,13 @@ MultiArg::MultiArg(const std::string& flag, bool req, const std::string& typeDesc, Visitor* v) : - Arg( flag, name, desc, req, true, v ), + Arg( flag, name, desc, req, true, v ), _values(std::vector()), _typeDesc( typeDesc ), _constraint( NULL ), _allowMore(false) { - _acceptsMultipleValues = true; + _acceptsMultipleValues = true; } template @@ -254,14 +261,14 @@ MultiArg::MultiArg(const std::string& flag, const std::string& typeDesc, CmdLineInterface& parser, Visitor* v) -: Arg( flag, name, desc, req, true, v ), - _values(std::vector()), - _typeDesc( typeDesc ), - _constraint( NULL ), - _allowMore(false) + : Arg( flag, name, desc, req, true, v ), + _values(std::vector()), + _typeDesc( typeDesc ), + _constraint( NULL ), + _allowMore(false) { - parser.add( this ); - _acceptsMultipleValues = true; + parser.add( this ); + _acceptsMultipleValues = true; } /** @@ -274,13 +281,13 @@ MultiArg::MultiArg(const std::string& flag, bool req, Constraint* constraint, Visitor* v) -: Arg( flag, name, desc, req, true, v ), - _values(std::vector()), - _typeDesc( constraint->shortID() ), - _constraint( constraint ), - _allowMore(false) + : Arg( flag, name, desc, req, true, v ), + _values(std::vector()), + _typeDesc( constraint->shortID() ), + _constraint( constraint ), + _allowMore(false) { - _acceptsMultipleValues = true; + _acceptsMultipleValues = true; } template @@ -291,68 +298,63 @@ MultiArg::MultiArg(const std::string& flag, Constraint* constraint, CmdLineInterface& parser, Visitor* v) -: Arg( flag, name, desc, req, true, v ), - _values(std::vector()), - _typeDesc( constraint->shortID() ), - _constraint( constraint ), - _allowMore(false) + : Arg( flag, name, desc, req, true, v ), + _values(std::vector()), + _typeDesc( constraint->shortID() ), + _constraint( constraint ), + _allowMore(false) { - parser.add( this ); - _acceptsMultipleValues = true; + parser.add( this ); + _acceptsMultipleValues = true; } template -const std::vector& MultiArg::getValue() { return _values; } +const std::vector& MultiArg::getValue() +{ + return _values; +} template bool MultiArg::processArg(int *i, std::vector& args) { - if ( _ignoreable && Arg::ignoreRest() ) - return false; - - if ( _hasBlanks( args[*i] ) ) - return false; - - std::string flag = args[*i]; - std::string value = ""; - - trimFlag( flag, value ); - - if ( argMatches( flag ) ) - { - if ( Arg::delimiter() != ' ' && value == "" ) - throw( ArgParseException( - "Couldn't find delimiter for this argument!", - toString() ) ); - - // always take the first one, regardless of start string - if ( value == "" ) - { - (*i)++; - if ( static_cast(*i) < args.size() ) - _extractValue( args[*i] ); - else - throw( ArgParseException("Missing a value for this argument!", - toString() ) ); - } - else - _extractValue( value ); - - /* - // continuing taking the args until we hit one with a start string - while ( (unsigned int)(*i)+1 < args.size() && - args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 && - args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) - _extractValue( args[++(*i)] ); - */ - - _alreadySet = true; - _checkWithVisitor(); - - return true; - } - else - return false; + if ( _ignoreable && Arg::ignoreRest() ) + return false; + if ( _hasBlanks( args[*i] ) ) + return false; + std::string flag = args[*i]; + std::string value = ""; + trimFlag( flag, value ); + if ( argMatches( flag ) ) + { + if ( Arg::delimiter() != ' ' && value == "" ) + throw( ArgParseException( + "Couldn't find delimiter for this argument!", + toString() ) ); + // always take the first one, regardless of start string + if ( value == "" ) + { + (*i)++; + if ( static_cast(*i) < args.size() ) + _extractValue( args[*i] ); + else + throw( ArgParseException("Missing a value for this argument!", + toString() ) ); + } + else + _extractValue( value ); + /* + // continuing taking the args until we hit one with a start string + while ( (unsigned int)(*i)+1 < args.size() && + args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 && + args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) + _extractValue( args[++(*i)] ); + */ + _alreadySet = true; + _checkWithVisitor(); + return true; + } + else + return false; } /** @@ -361,8 +363,8 @@ bool MultiArg::processArg(int *i, std::vector& args) template std::string MultiArg::shortID(const std::string& val) const { - static_cast(val); // Ignore input, don't warn - return Arg::shortID(_typeDesc) + " ... "; + static_cast(val); // Ignore input, don't warn + return Arg::shortID(_typeDesc) + " ... "; } /** @@ -371,8 +373,8 @@ std::string MultiArg::shortID(const std::string& val) const template std::string MultiArg::longID(const std::string& val) const { - static_cast(val); // Ignore input, don't warn - return Arg::longID(_typeDesc) + " (accepted multiple times)"; + static_cast(val); // Ignore input, don't warn + return Arg::longID(_typeDesc) + " (accepted multiple times)"; } /** @@ -382,50 +384,51 @@ std::string MultiArg::longID(const std::string& val) const template bool MultiArg::isRequired() const { - if ( _required ) - { - if ( _values.size() > 1 ) - return false; - else - return true; - } - else - return false; - + if ( _required ) + { + if ( _values.size() > 1 ) + return false; + else + return true; + } + else + return false; } template void MultiArg::_extractValue( const std::string& val ) { - try { - T tmp; - ExtractValue(tmp, val, typename ArgTraits::ValueCategory()); - _values.push_back(tmp); - } catch( ArgParseException &e) { - throw ArgParseException(e.error(), toString()); - } - - if ( _constraint != NULL ) - if ( ! _constraint->check( _values.back() ) ) - throw( CmdLineParseException( "Value '" + val + - "' does not meet constraint: " + - _constraint->description(), - toString() ) ); + try + { + T tmp; + ExtractValue(tmp, val, typename ArgTraits::ValueCategory()); + _values.push_back(tmp); + } + catch( ArgParseException &e) + { + throw ArgParseException(e.error(), toString()); + } + if ( _constraint != NULL ) + if ( ! _constraint->check( _values.back() ) ) + throw( CmdLineParseException( "Value '" + val + + "' does not meet constraint: " + + _constraint->description(), + toString() ) ); } template bool MultiArg::allowMore() { - bool am = _allowMore; - _allowMore = true; - return am; + bool am = _allowMore; + _allowMore = true; + return am; } template void MultiArg::reset() { - Arg::reset(); - _values.clear(); + Arg::reset(); + _values.clear(); } } // namespace TCLAP diff --git a/src/tclap/MultiSwitchArg.h b/src/tclap/MultiSwitchArg.h index af3192f..4beb950 100644 --- a/src/tclap/MultiSwitchArg.h +++ b/src/tclap/MultiSwitchArg.h @@ -30,7 +30,8 @@ #include "SwitchArg.h" -namespace TCLAP { +namespace TCLAP +{ /** * A multiple switch argument. If the switch is set on the command line, then @@ -38,89 +39,89 @@ namespace TCLAP { */ class MultiSwitchArg : public SwitchArg { - protected: + protected: - /** - * The value of the switch. - */ - int _value; + /** + * The value of the switch. + */ + int _value; - /** - * Used to support the reset() method so that ValueArg can be - * reset to their constructed value. - */ - int _default; + /** + * Used to support the reset() method so that ValueArg can be + * reset to their constructed value. + */ + int _default; - public: + public: - /** - * MultiSwitchArg constructor. - * \param flag - The one character flag that identifies this - * argument on the command line. - * \param name - A one word name for the argument. Can be - * used as a long flag on the command line. - * \param desc - A description of what the argument is for or - * does. - * \param init - Optional. The initial/default value of this Arg. - * Defaults to 0. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - MultiSwitchArg(const std::string& flag, - const std::string& name, - const std::string& desc, - int init = 0, - Visitor* v = NULL); + /** + * MultiSwitchArg constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param init - Optional. The initial/default value of this Arg. + * Defaults to 0. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + MultiSwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, + int init = 0, + Visitor* v = NULL); - /** - * MultiSwitchArg constructor. - * \param flag - The one character flag that identifies this - * argument on the command line. - * \param name - A one word name for the argument. Can be - * used as a long flag on the command line. - * \param desc - A description of what the argument is for or - * does. - * \param parser - A CmdLine parser object to add this Arg to - * \param init - Optional. The initial/default value of this Arg. - * Defaults to 0. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - MultiSwitchArg(const std::string& flag, - const std::string& name, - const std::string& desc, - CmdLineInterface& parser, - int init = 0, - Visitor* v = NULL); + /** + * MultiSwitchArg constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param parser - A CmdLine parser object to add this Arg to + * \param init - Optional. The initial/default value of this Arg. + * Defaults to 0. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + MultiSwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, + CmdLineInterface& parser, + int init = 0, + Visitor* v = NULL); - /** - * Handles the processing of the argument. - * This re-implements the SwitchArg version of this method to set the - * _value of the argument appropriately. - * \param i - Pointer the the current argument in the list. - * \param args - Mutable list of strings. Passed - * in from main(). - */ - virtual bool processArg(int* i, std::vector& args); + /** + * Handles the processing of the argument. + * This re-implements the SwitchArg version of this method to set the + * _value of the argument appropriately. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. Passed + * in from main(). + */ + virtual bool processArg(int* i, std::vector& args); - /** - * Returns int, the number of times the switch has been set. - */ - int getValue(); + /** + * Returns int, the number of times the switch has been set. + */ + int getValue(); - /** - * Returns the shortID for this Arg. - */ - std::string shortID(const std::string& val) const; + /** + * Returns the shortID for this Arg. + */ + std::string shortID(const std::string& val) const; - /** - * Returns the longID for this Arg. - */ - std::string longID(const std::string& val) const; + /** + * Returns the longID for this Arg. + */ + std::string longID(const std::string& val) const; - void reset(); + void reset(); }; @@ -128,83 +129,78 @@ class MultiSwitchArg : public SwitchArg //BEGIN MultiSwitchArg.cpp ////////////////////////////////////////////////////////////////////// inline MultiSwitchArg::MultiSwitchArg(const std::string& flag, - const std::string& name, - const std::string& desc, - int init, - Visitor* v ) -: SwitchArg(flag, name, desc, false, v), -_value( init ), -_default( init ) + const std::string& name, + const std::string& desc, + int init, + Visitor* v ) + : SwitchArg(flag, name, desc, false, v), + _value( init ), + _default( init ) { } inline MultiSwitchArg::MultiSwitchArg(const std::string& flag, - const std::string& name, - const std::string& desc, - CmdLineInterface& parser, - int init, - Visitor* v ) -: SwitchArg(flag, name, desc, false, v), -_value( init ), -_default( init ) + const std::string& name, + const std::string& desc, + CmdLineInterface& parser, + int init, + Visitor* v ) + : SwitchArg(flag, name, desc, false, v), + _value( init ), + _default( init ) { - parser.add( this ); + parser.add( this ); } -inline int MultiSwitchArg::getValue() { return _value; } +inline int MultiSwitchArg::getValue() +{ + return _value; +} inline bool MultiSwitchArg::processArg(int *i, std::vector& args) { - if ( _ignoreable && Arg::ignoreRest() ) - return false; - - if ( argMatches( args[*i] )) - { - // so the isSet() method will work - _alreadySet = true; - - // Matched argument: increment value. - ++_value; - - _checkWithVisitor(); - - return true; - } - else if ( combinedSwitchesMatch( args[*i] ) ) - { - // so the isSet() method will work - _alreadySet = true; - - // Matched argument: increment value. - ++_value; - - // Check for more in argument and increment value. - while ( combinedSwitchesMatch( args[*i] ) ) - ++_value; - - _checkWithVisitor(); - - return false; - } - else - return false; + if ( _ignoreable && Arg::ignoreRest() ) + return false; + if ( argMatches( args[*i] )) + { + // so the isSet() method will work + _alreadySet = true; + // Matched argument: increment value. + ++_value; + _checkWithVisitor(); + return true; + } + else if ( combinedSwitchesMatch( args[*i] ) ) + { + // so the isSet() method will work + _alreadySet = true; + // Matched argument: increment value. + ++_value; + // Check for more in argument and increment value. + while ( combinedSwitchesMatch( args[*i] ) ) + ++_value; + _checkWithVisitor(); + return false; + } + else + return false; } inline std::string MultiSwitchArg::shortID(const std::string& val) const { - return Arg::shortID(val) + " ... "; + return Arg::shortID(val) + " ... "; } inline std::string MultiSwitchArg::longID(const std::string& val) const { - return Arg::longID(val) + " (accepted multiple times)"; + return Arg::longID(val) + " (accepted multiple times)"; } inline void MultiSwitchArg::reset() { - MultiSwitchArg::_value = MultiSwitchArg::_default; + MultiSwitchArg::_value = MultiSwitchArg::_default; } ////////////////////////////////////////////////////////////////////// diff --git a/src/tclap/OptionalUnlabeledTracker.h b/src/tclap/OptionalUnlabeledTracker.h index f06be14..a0ec8f4 100644 --- a/src/tclap/OptionalUnlabeledTracker.h +++ b/src/tclap/OptionalUnlabeledTracker.h @@ -26,34 +26,44 @@ #include -namespace TCLAP { +namespace TCLAP +{ class OptionalUnlabeledTracker { - public: + public: - static void check( bool req, const std::string& argName ); + static void check( bool req, const std::string& argName ); - static void gotOptional() { alreadyOptionalRef() = true; } + static void gotOptional() + { + alreadyOptionalRef() = true; + } - static bool& alreadyOptional() { return alreadyOptionalRef(); } + static bool& alreadyOptional() + { + return alreadyOptionalRef(); + } - private: + private: - static bool& alreadyOptionalRef() { static bool ct = false; return ct; } + static bool& alreadyOptionalRef() + { + static bool ct = false; + return ct; + } }; inline void OptionalUnlabeledTracker::check( bool req, const std::string& argName ) { - if ( OptionalUnlabeledTracker::alreadyOptional() ) - throw( SpecificationException( - "You can't specify ANY Unlabeled Arg following an optional Unlabeled Arg", - argName ) ); - - if ( !req ) - OptionalUnlabeledTracker::gotOptional(); + if ( OptionalUnlabeledTracker::alreadyOptional() ) + throw( SpecificationException( + "You can't specify ANY Unlabeled Arg following an optional Unlabeled Arg", + argName ) ); + if ( !req ) + OptionalUnlabeledTracker::gotOptional(); } diff --git a/src/tclap/StandardTraits.h b/src/tclap/StandardTraits.h index 9e678ba..f563bdb 100644 --- a/src/tclap/StandardTraits.h +++ b/src/tclap/StandardTraits.h @@ -39,7 +39,8 @@ #endif #endif -namespace TCLAP { +namespace TCLAP +{ // ====================================================================== // Integer types @@ -49,32 +50,36 @@ namespace TCLAP { * longs have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; /** * ints have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; /** * shorts have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; /** * chars have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; #ifdef HAVE_LONG_LONG @@ -82,8 +87,9 @@ struct ArgTraits { * long longs have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; #endif @@ -95,32 +101,36 @@ struct ArgTraits { * unsigned longs have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; /** * unsigned ints have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; /** * unsigned shorts have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; /** * unsigned chars have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; // Microsoft implements size_t awkwardly. @@ -129,8 +139,9 @@ struct ArgTraits { * size_ts have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; #endif @@ -140,8 +151,9 @@ struct ArgTraits { * unsigned long longs have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; #endif @@ -153,16 +165,18 @@ struct ArgTraits { * floats have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; /** * doubles have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; // ====================================================================== @@ -173,8 +187,9 @@ struct ArgTraits { * bools have value-like semantics. */ template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; @@ -183,8 +198,9 @@ struct ArgTraits { */ #ifndef TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS template<> -struct ArgTraits { - typedef ValueLike ValueCategory; +struct ArgTraits +{ + typedef ValueLike ValueCategory; }; #endif @@ -192,14 +208,15 @@ struct ArgTraits { * Strings have string like argument traits. */ template<> -struct ArgTraits { - typedef StringLike ValueCategory; +struct ArgTraits +{ + typedef StringLike ValueCategory; }; template void SetString(T &dst, const std::string &src) { - dst = src; + dst = src; } } // namespace diff --git a/src/tclap/StdOutput.h b/src/tclap/StdOutput.h index cc7260e..6807b09 100644 --- a/src/tclap/StdOutput.h +++ b/src/tclap/StdOutput.h @@ -34,7 +34,8 @@ #include "XorHandler.h" #include "Arg.h" -namespace TCLAP { +namespace TCLAP +{ /** * A class that isolates any output from the CmdLine object so that it @@ -43,255 +44,223 @@ namespace TCLAP { class StdOutput : public CmdLineOutput { - public: + public: - /** - * Prints the usage to stdout. Can be overridden to - * produce alternative behavior. - * \param c - The CmdLine object the output is generated for. - */ - virtual void usage(CmdLineInterface& c); + /** + * Prints the usage to stdout. Can be overridden to + * produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void usage(CmdLineInterface& c); - /** - * Prints the version to stdout. Can be overridden - * to produce alternative behavior. - * \param c - The CmdLine object the output is generated for. - */ - virtual void version(CmdLineInterface& c); + /** + * Prints the version to stdout. Can be overridden + * to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void version(CmdLineInterface& c); - /** - * Prints (to stderr) an error message, short usage - * Can be overridden to produce alternative behavior. - * \param c - The CmdLine object the output is generated for. - * \param e - The ArgException that caused the failure. - */ - virtual void failure(CmdLineInterface& c, - ArgException& e ); + /** + * Prints (to stderr) an error message, short usage + * Can be overridden to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. + */ + virtual void failure(CmdLineInterface& c, + ArgException& e ); - protected: + protected: - /** - * Writes a brief usage message with short args. - * \param c - The CmdLine object the output is generated for. - * \param os - The stream to write the message to. - */ - void _shortUsage( CmdLineInterface& c, std::ostream& os ) const; + /** + * Writes a brief usage message with short args. + * \param c - The CmdLine object the output is generated for. + * \param os - The stream to write the message to. + */ + void _shortUsage( CmdLineInterface& c, std::ostream& os ) const; - /** - * Writes a longer usage message with long and short args, - * provides descriptions and prints message. - * \param c - The CmdLine object the output is generated for. - * \param os - The stream to write the message to. - */ - void _longUsage( CmdLineInterface& c, std::ostream& os ) const; + /** + * Writes a longer usage message with long and short args, + * provides descriptions and prints message. + * \param c - The CmdLine object the output is generated for. + * \param os - The stream to write the message to. + */ + void _longUsage( CmdLineInterface& c, std::ostream& os ) const; - /** - * This function inserts line breaks and indents long strings - * according the params input. It will only break lines at spaces, - * commas and pipes. - * \param os - The stream to be printed to. - * \param s - The string to be printed. - * \param maxWidth - The maxWidth allowed for the output line. - * \param indentSpaces - The number of spaces to indent the first line. - * \param secondLineOffset - The number of spaces to indent the second - * and all subsequent lines in addition to indentSpaces. - */ - void spacePrint( std::ostream& os, - const std::string& s, - int maxWidth, - int indentSpaces, - int secondLineOffset ) const; + /** + * This function inserts line breaks and indents long strings + * according the params input. It will only break lines at spaces, + * commas and pipes. + * \param os - The stream to be printed to. + * \param s - The string to be printed. + * \param maxWidth - The maxWidth allowed for the output line. + * \param indentSpaces - The number of spaces to indent the first line. + * \param secondLineOffset - The number of spaces to indent the second + * and all subsequent lines in addition to indentSpaces. + */ + void spacePrint( std::ostream& os, + const std::string& s, + int maxWidth, + int indentSpaces, + int secondLineOffset ) const; }; inline void StdOutput::version(CmdLineInterface& _cmd) { - std::string progName = _cmd.getProgramName(); - std::string xversion = _cmd.getVersion(); - - std::cout << std::endl << progName << " version: " - << xversion << std::endl << std::endl; + std::string progName = _cmd.getProgramName(); + std::string xversion = _cmd.getVersion(); + std::cout << std::endl << progName << " version: " + << xversion << std::endl << std::endl; } inline void StdOutput::usage(CmdLineInterface& _cmd ) { - std::cout << std::endl << "USAGE: " << std::endl << std::endl; - - _shortUsage( _cmd, std::cout ); - - std::cout << std::endl << std::endl << "Where: " << std::endl << std::endl; - - _longUsage( _cmd, std::cout ); - - std::cout << std::endl; - + std::cout << std::endl << "USAGE: " << std::endl << std::endl; + _shortUsage( _cmd, std::cout ); + std::cout << std::endl << std::endl << "Where: " << std::endl << std::endl; + _longUsage( _cmd, std::cout ); + std::cout << std::endl; } inline void StdOutput::failure( CmdLineInterface& _cmd, - ArgException& e ) + ArgException& e ) { - std::string progName = _cmd.getProgramName(); - - std::cerr << "PARSE ERROR: " << e.argId() << std::endl - << " " << e.error() << std::endl << std::endl; - - if ( _cmd.hasHelpAndVersion() ) - { - std::cerr << "Brief USAGE: " << std::endl; - - _shortUsage( _cmd, std::cerr ); - - std::cerr << std::endl << "For complete USAGE and HELP type: " - << std::endl << " " << progName << " --help" - << std::endl << std::endl; - } - else - usage(_cmd); - - throw ExitException(1); + std::string progName = _cmd.getProgramName(); + std::cerr << "PARSE ERROR: " << e.argId() << std::endl + << " " << e.error() << std::endl << std::endl; + if ( _cmd.hasHelpAndVersion() ) + { + std::cerr << "Brief USAGE: " << std::endl; + _shortUsage( _cmd, std::cerr ); + std::cerr << std::endl << "For complete USAGE and HELP type: " + << std::endl << " " << progName << " --help" + << std::endl << std::endl; + } + else + usage(_cmd); + throw ExitException(1); } inline void StdOutput::_shortUsage( CmdLineInterface& _cmd, - std::ostream& os ) const + std::ostream& os ) const { - std::list argList = _cmd.getArgList(); - std::string progName = _cmd.getProgramName(); - XorHandler xorHandler = _cmd.getXorHandler(); - std::vector< std::vector > xorList = xorHandler.getXorList(); - - std::string s = progName + " "; - - // first the xor - for ( int i = 0; static_cast(i) < xorList.size(); i++ ) - { - s += " {"; - for ( ArgVectorIterator it = xorList[i].begin(); - it != xorList[i].end(); it++ ) - s += (*it)->shortID() + "|"; - - s[s.length()-1] = '}'; - } - - // then the rest - for (ArgListIterator it = argList.begin(); it != argList.end(); it++) - if ( !xorHandler.contains( (*it) ) ) - s += " " + (*it)->shortID(); - - // if the program name is too long, then adjust the second line offset - int secondLineOffset = static_cast(progName.length()) + 2; - if ( secondLineOffset > 75/2 ) - secondLineOffset = static_cast(75/2); - - spacePrint( os, s, 75, 3, secondLineOffset ); + std::list argList = _cmd.getArgList(); + std::string progName = _cmd.getProgramName(); + XorHandler xorHandler = _cmd.getXorHandler(); + std::vector< std::vector > xorList = xorHandler.getXorList(); + std::string s = progName + " "; + // first the xor + for ( int i = 0; static_cast(i) < xorList.size(); i++ ) + { + s += " {"; + for ( ArgVectorIterator it = xorList[i].begin(); + it != xorList[i].end(); it++ ) + s += (*it)->shortID() + "|"; + s[s.length()-1] = '}'; + } + // then the rest + for (ArgListIterator it = argList.begin(); it != argList.end(); it++) + if ( !xorHandler.contains( (*it) ) ) + s += " " + (*it)->shortID(); + // if the program name is too long, then adjust the second line offset + int secondLineOffset = static_cast(progName.length()) + 2; + if ( secondLineOffset > 75/2 ) + secondLineOffset = static_cast(75/2); + spacePrint( os, s, 75, 3, secondLineOffset ); } inline void StdOutput::_longUsage( CmdLineInterface& _cmd, - std::ostream& os ) const + std::ostream& os ) const { - std::list argList = _cmd.getArgList(); - std::string message = _cmd.getMessage(); - XorHandler xorHandler = _cmd.getXorHandler(); - std::vector< std::vector > xorList = xorHandler.getXorList(); - - // first the xor - for ( int i = 0; static_cast(i) < xorList.size(); i++ ) - { - for ( ArgVectorIterator it = xorList[i].begin(); - it != xorList[i].end(); - it++ ) - { - spacePrint( os, (*it)->longID(), 75, 3, 3 ); - spacePrint( os, (*it)->getDescription(), 75, 5, 0 ); - - if ( it+1 != xorList[i].end() ) - spacePrint(os, "-- OR --", 75, 9, 0); - } - os << std::endl << std::endl; - } - - // then the rest - for (ArgListIterator it = argList.begin(); it != argList.end(); it++) - if ( !xorHandler.contains( (*it) ) ) - { - spacePrint( os, (*it)->longID(), 75, 3, 3 ); - spacePrint( os, (*it)->getDescription(), 75, 5, 0 ); - os << std::endl; - } - - os << std::endl; - - spacePrint( os, message, 75, 3, 0 ); + std::list argList = _cmd.getArgList(); + std::string message = _cmd.getMessage(); + XorHandler xorHandler = _cmd.getXorHandler(); + std::vector< std::vector > xorList = xorHandler.getXorList(); + // first the xor + for ( int i = 0; static_cast(i) < xorList.size(); i++ ) + { + for ( ArgVectorIterator it = xorList[i].begin(); + it != xorList[i].end(); + it++ ) + { + spacePrint( os, (*it)->longID(), 75, 3, 3 ); + spacePrint( os, (*it)->getDescription(), 75, 5, 0 ); + if ( it+1 != xorList[i].end() ) + spacePrint(os, "-- OR --", 75, 9, 0); + } + os << std::endl << std::endl; + } + // then the rest + for (ArgListIterator it = argList.begin(); it != argList.end(); it++) + if ( !xorHandler.contains( (*it) ) ) + { + spacePrint( os, (*it)->longID(), 75, 3, 3 ); + spacePrint( os, (*it)->getDescription(), 75, 5, 0 ); + os << std::endl; + } + os << std::endl; + spacePrint( os, message, 75, 3, 0 ); } inline void StdOutput::spacePrint( std::ostream& os, - const std::string& s, - int maxWidth, - int indentSpaces, - int secondLineOffset ) const + const std::string& s, + int maxWidth, + int indentSpaces, + int secondLineOffset ) const { - int len = static_cast(s.length()); - - if ( (len + indentSpaces > maxWidth) && maxWidth > 0 ) - { - int allowedLen = maxWidth - indentSpaces; - int start = 0; - while ( start < len ) - { - // find the substring length - // int stringLen = std::min( len - start, allowedLen ); - // doing it this way to support a VisualC++ 2005 bug - using namespace std; - int stringLen = min( len - start, allowedLen ); - - // trim the length so it doesn't end in middle of a word - if ( stringLen == allowedLen ) - while ( stringLen >= 0 && - s[stringLen+start] != ' ' && - s[stringLen+start] != ',' && - s[stringLen+start] != '|' ) - stringLen--; - - // ok, the word is longer than the line, so just split - // wherever the line ends - if ( stringLen <= 0 ) - stringLen = allowedLen; - - // check for newlines - for ( int i = 0; i < stringLen; i++ ) - if ( s[start+i] == '\n' ) - stringLen = i+1; - - // print the indent - for ( int i = 0; i < indentSpaces; i++ ) - os << " "; - - if ( start == 0 ) - { - // handle second line offsets - indentSpaces += secondLineOffset; - - // adjust allowed len - allowedLen -= secondLineOffset; - } - - os << s.substr(start,stringLen) << std::endl; - - // so we don't start a line with a space - while ( s[stringLen+start] == ' ' && start < len ) - start++; - - start += stringLen; - } - } - else - { - for ( int i = 0; i < indentSpaces; i++ ) - os << " "; - os << s << std::endl; - } + int len = static_cast(s.length()); + if ( (len + indentSpaces > maxWidth) && maxWidth > 0 ) + { + int allowedLen = maxWidth - indentSpaces; + int start = 0; + while ( start < len ) + { + // find the substring length + // int stringLen = std::min( len - start, allowedLen ); + // doing it this way to support a VisualC++ 2005 bug + using namespace std; + int stringLen = min( len - start, allowedLen ); + // trim the length so it doesn't end in middle of a word + if ( stringLen == allowedLen ) + while ( stringLen >= 0 && + s[stringLen+start] != ' ' && + s[stringLen+start] != ',' && + s[stringLen+start] != '|' ) + stringLen--; + // ok, the word is longer than the line, so just split + // wherever the line ends + if ( stringLen <= 0 ) + stringLen = allowedLen; + // check for newlines + for ( int i = 0; i < stringLen; i++ ) + if ( s[start+i] == '\n' ) + stringLen = i+1; + // print the indent + for ( int i = 0; i < indentSpaces; i++ ) + os << " "; + if ( start == 0 ) + { + // handle second line offsets + indentSpaces += secondLineOffset; + // adjust allowed len + allowedLen -= secondLineOffset; + } + os << s.substr(start,stringLen) << std::endl; + // so we don't start a line with a space + while ( s[stringLen+start] == ' ' && start < len ) + start++; + start += stringLen; + } + } + else + { + for ( int i = 0; i < indentSpaces; i++ ) + os << " "; + os << s << std::endl; + } } } //namespace TCLAP diff --git a/src/tclap/SwitchArg.h b/src/tclap/SwitchArg.h index 74f4bf0..2702723 100644 --- a/src/tclap/SwitchArg.h +++ b/src/tclap/SwitchArg.h @@ -29,7 +29,8 @@ #include "Arg.h" -namespace TCLAP { +namespace TCLAP +{ /** * A simple switch argument. If the switch is set on the command line, then @@ -38,95 +39,95 @@ namespace TCLAP { */ class SwitchArg : public Arg { - protected: + protected: - /** - * The value of the switch. - */ - bool _value; + /** + * The value of the switch. + */ + bool _value; - /** - * Used to support the reset() method so that ValueArg can be - * reset to their constructed value. - */ - bool _default; + /** + * Used to support the reset() method so that ValueArg can be + * reset to their constructed value. + */ + bool _default; - public: + public: - /** - * SwitchArg constructor. - * \param flag - The one character flag that identifies this - * argument on the command line. - * \param name - A one word name for the argument. Can be - * used as a long flag on the command line. - * \param desc - A description of what the argument is for or - * does. - * \param def - The default value for this Switch. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - SwitchArg(const std::string& flag, - const std::string& name, - const std::string& desc, - bool def = false, - Visitor* v = NULL); + /** + * SwitchArg constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param def - The default value for this Switch. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + SwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool def = false, + Visitor* v = NULL); - /** - * SwitchArg constructor. - * \param flag - The one character flag that identifies this - * argument on the command line. - * \param name - A one word name for the argument. Can be - * used as a long flag on the command line. - * \param desc - A description of what the argument is for or - * does. - * \param parser - A CmdLine parser object to add this Arg to - * \param def - The default value for this Switch. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - SwitchArg(const std::string& flag, - const std::string& name, - const std::string& desc, - CmdLineInterface& parser, - bool def = false, - Visitor* v = NULL); + /** + * SwitchArg constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param parser - A CmdLine parser object to add this Arg to + * \param def - The default value for this Switch. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + SwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, + CmdLineInterface& parser, + bool def = false, + Visitor* v = NULL); - /** - * Handles the processing of the argument. - * This re-implements the Arg version of this method to set the - * _value of the argument appropriately. - * \param i - Pointer the the current argument in the list. - * \param args - Mutable list of strings. Passed - * in from main(). - */ - virtual bool processArg(int* i, std::vector& args); + /** + * Handles the processing of the argument. + * This re-implements the Arg version of this method to set the + * _value of the argument appropriately. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. Passed + * in from main(). + */ + virtual bool processArg(int* i, std::vector& args); - /** - * Checks a string to see if any of the chars in the string - * match the flag for this Switch. - */ - bool combinedSwitchesMatch(std::string& combined); + /** + * Checks a string to see if any of the chars in the string + * match the flag for this Switch. + */ + bool combinedSwitchesMatch(std::string& combined); - /** - * Returns bool, whether or not the switch has been set. - */ - bool getValue(); + /** + * Returns bool, whether or not the switch has been set. + */ + bool getValue(); - virtual void reset(); + virtual void reset(); - private: - /** - * Checks to see if we've found the last match in - * a combined string. - */ - bool lastCombined(std::string& combined); + private: + /** + * Checks to see if we've found the last match in + * a combined string. + */ + bool lastCombined(std::string& combined); - /** - * Does the common processing of processArg. - */ - void commonProcessing(); + /** + * Does the common processing of processArg. + */ + void commonProcessing(); }; ////////////////////////////////////////////////////////////////////// @@ -137,9 +138,9 @@ inline SwitchArg::SwitchArg(const std::string& flag, const std::string& desc, bool default_val, Visitor* v ) -: Arg(flag, name, desc, false, false, v), - _value( default_val ), - _default( default_val ) + : Arg(flag, name, desc, false, false, v), + _value( default_val ), + _default( default_val ) { } inline SwitchArg::SwitchArg(const std::string& flag, @@ -148,114 +149,104 @@ inline SwitchArg::SwitchArg(const std::string& flag, CmdLineInterface& parser, bool default_val, Visitor* v ) -: Arg(flag, name, desc, false, false, v), - _value( default_val ), - _default(default_val) + : Arg(flag, name, desc, false, false, v), + _value( default_val ), + _default(default_val) { - parser.add( this ); + parser.add( this ); } -inline bool SwitchArg::getValue() { return _value; } +inline bool SwitchArg::getValue() +{ + return _value; +} inline bool SwitchArg::lastCombined(std::string& combinedSwitches ) { - for ( unsigned int i = 1; i < combinedSwitches.length(); i++ ) - if ( combinedSwitches[i] != Arg::blankChar() ) - return false; - - return true; + for ( unsigned int i = 1; i < combinedSwitches.length(); i++ ) + if ( combinedSwitches[i] != Arg::blankChar() ) + return false; + return true; } inline bool SwitchArg::combinedSwitchesMatch(std::string& combinedSwitches ) { - // make sure this is actually a combined switch - if ( combinedSwitches.length() > 0 && - combinedSwitches[0] != Arg::flagStartString()[0] ) - return false; - - // make sure it isn't a long name - if ( combinedSwitches.substr( 0, Arg::nameStartString().length() ) == - Arg::nameStartString() ) - return false; - - // make sure the delimiter isn't in the string - if ( combinedSwitches.find_first_of( Arg::delimiter() ) != std::string::npos ) - return false; - - // ok, we're not specifying a ValueArg, so we know that we have - // a combined switch list. - for ( unsigned int i = 1; i < combinedSwitches.length(); i++ ) - if ( _flag.length() > 0 && - combinedSwitches[i] == _flag[0] && - _flag[0] != Arg::flagStartString()[0] ) - { - // update the combined switches so this one is no longer present - // this is necessary so that no unlabeled args are matched - // later in the processing. - //combinedSwitches.erase(i,1); - combinedSwitches[i] = Arg::blankChar(); - return true; - } - - // none of the switches passed in the list match. - return false; + // make sure this is actually a combined switch + if ( combinedSwitches.length() > 0 && + combinedSwitches[0] != Arg::flagStartString()[0] ) + return false; + // make sure it isn't a long name + if ( combinedSwitches.substr( 0, Arg::nameStartString().length() ) == + Arg::nameStartString() ) + return false; + // make sure the delimiter isn't in the string + if ( combinedSwitches.find_first_of( Arg::delimiter() ) != std::string::npos ) + return false; + // ok, we're not specifying a ValueArg, so we know that we have + // a combined switch list. + for ( unsigned int i = 1; i < combinedSwitches.length(); i++ ) + if ( _flag.length() > 0 && + combinedSwitches[i] == _flag[0] && + _flag[0] != Arg::flagStartString()[0] ) + { + // update the combined switches so this one is no longer present + // this is necessary so that no unlabeled args are matched + // later in the processing. + //combinedSwitches.erase(i,1); + combinedSwitches[i] = Arg::blankChar(); + return true; + } + // none of the switches passed in the list match. + return false; } inline void SwitchArg::commonProcessing() { - if ( _xorSet ) - throw(CmdLineParseException( - "Mutually exclusive argument already set!", toString())); - - if ( _alreadySet ) - throw(CmdLineParseException("Argument already set!", toString())); - - _alreadySet = true; - - if ( _value == true ) - _value = false; - else - _value = true; - - _checkWithVisitor(); + if ( _xorSet ) + throw(CmdLineParseException( + "Mutually exclusive argument already set!", toString())); + if ( _alreadySet ) + throw(CmdLineParseException("Argument already set!", toString())); + _alreadySet = true; + if ( _value == true ) + _value = false; + else + _value = true; + _checkWithVisitor(); } inline bool SwitchArg::processArg(int *i, std::vector& args) { - if ( _ignoreable && Arg::ignoreRest() ) - return false; - - // if the whole string matches the flag or name string - if ( argMatches( args[*i] ) ) - { - commonProcessing(); - - return true; - } - // if a substring matches the flag as part of a combination - else if ( combinedSwitchesMatch( args[*i] ) ) - { - // check again to ensure we don't misinterpret - // this as a MultiSwitchArg - if ( combinedSwitchesMatch( args[*i] ) ) - throw(CmdLineParseException("Argument already set!", - toString())); - - commonProcessing(); - - // We only want to return true if we've found the last combined - // match in the string, otherwise we return true so that other - // switches in the combination will have a chance to match. - return lastCombined( args[*i] ); - } - else - return false; + if ( _ignoreable && Arg::ignoreRest() ) + return false; + // if the whole string matches the flag or name string + if ( argMatches( args[*i] ) ) + { + commonProcessing(); + return true; + } + // if a substring matches the flag as part of a combination + else if ( combinedSwitchesMatch( args[*i] ) ) + { + // check again to ensure we don't misinterpret + // this as a MultiSwitchArg + if ( combinedSwitchesMatch( args[*i] ) ) + throw(CmdLineParseException("Argument already set!", + toString())); + commonProcessing(); + // We only want to return true if we've found the last combined + // match in the string, otherwise we return true so that other + // switches in the combination will have a chance to match. + return lastCombined( args[*i] ); + } + else + return false; } inline void SwitchArg::reset() { - Arg::reset(); - _value = _default; + Arg::reset(); + _value = _default; } ////////////////////////////////////////////////////////////////////// //End SwitchArg.cpp diff --git a/src/tclap/UnlabeledMultiArg.h b/src/tclap/UnlabeledMultiArg.h index b0a3b73..0fc1b99 100644 --- a/src/tclap/UnlabeledMultiArg.h +++ b/src/tclap/UnlabeledMultiArg.h @@ -29,7 +29,8 @@ #include "MultiArg.h" #include "OptionalUnlabeledTracker.h" -namespace TCLAP { +namespace TCLAP +{ /** * Just like a MultiArg, except that the arguments are unlabeled. Basically, @@ -40,260 +41,253 @@ template class UnlabeledMultiArg : public MultiArg { - // If compiler has two stage name lookup (as gcc >= 3.4 does) - // this is requried to prevent undef. symbols - using MultiArg::_ignoreable; - using MultiArg::_hasBlanks; - using MultiArg::_extractValue; - using MultiArg::_typeDesc; - using MultiArg::_name; - using MultiArg::_description; - using MultiArg::_alreadySet; - using MultiArg::toString; + // If compiler has two stage name lookup (as gcc >= 3.4 does) + // this is requried to prevent undef. symbols + using MultiArg::_ignoreable; + using MultiArg::_hasBlanks; + using MultiArg::_extractValue; + using MultiArg::_typeDesc; + using MultiArg::_name; + using MultiArg::_description; + using MultiArg::_alreadySet; + using MultiArg::toString; - public: + public: - /** - * Constructor. - * \param name - The name of the Arg. Note that this is used for - * identification, not as a long flag. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param typeDesc - A short, human readable description of the - * type that this object expects. This is used in the generation - * of the USAGE statement. The goal is to be helpful to the end user - * of the program. - * \param ignoreable - Whether or not this argument can be ignored - * using the "--" flag. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - UnlabeledMultiArg( const std::string& name, - const std::string& desc, - bool req, - const std::string& typeDesc, - bool ignoreable = false, - Visitor* v = NULL ); - /** - * Constructor. - * \param name - The name of the Arg. Note that this is used for - * identification, not as a long flag. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param typeDesc - A short, human readable description of the - * type that this object expects. This is used in the generation - * of the USAGE statement. The goal is to be helpful to the end user - * of the program. - * \param parser - A CmdLine parser object to add this Arg to - * \param ignoreable - Whether or not this argument can be ignored - * using the "--" flag. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - UnlabeledMultiArg( const std::string& name, - const std::string& desc, - bool req, - const std::string& typeDesc, - CmdLineInterface& parser, - bool ignoreable = false, - Visitor* v = NULL ); + /** + * Constructor. + * \param name - The name of the Arg. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param ignoreable - Whether or not this argument can be ignored + * using the "--" flag. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + UnlabeledMultiArg( const std::string& name, + const std::string& desc, + bool req, + const std::string& typeDesc, + bool ignoreable = false, + Visitor* v = NULL ); + /** + * Constructor. + * \param name - The name of the Arg. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param parser - A CmdLine parser object to add this Arg to + * \param ignoreable - Whether or not this argument can be ignored + * using the "--" flag. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + UnlabeledMultiArg( const std::string& name, + const std::string& desc, + bool req, + const std::string& typeDesc, + CmdLineInterface& parser, + bool ignoreable = false, + Visitor* v = NULL ); - /** - * Constructor. - * \param name - The name of the Arg. Note that this is used for - * identification, not as a long flag. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param constraint - A pointer to a Constraint object used - * to constrain this Arg. - * \param ignoreable - Whether or not this argument can be ignored - * using the "--" flag. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - UnlabeledMultiArg( const std::string& name, - const std::string& desc, - bool req, - Constraint* constraint, - bool ignoreable = false, - Visitor* v = NULL ); + /** + * Constructor. + * \param name - The name of the Arg. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param ignoreable - Whether or not this argument can be ignored + * using the "--" flag. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + UnlabeledMultiArg( const std::string& name, + const std::string& desc, + bool req, + Constraint* constraint, + bool ignoreable = false, + Visitor* v = NULL ); - /** - * Constructor. - * \param name - The name of the Arg. Note that this is used for - * identification, not as a long flag. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param constraint - A pointer to a Constraint object used - * to constrain this Arg. - * \param parser - A CmdLine parser object to add this Arg to - * \param ignoreable - Whether or not this argument can be ignored - * using the "--" flag. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - UnlabeledMultiArg( const std::string& name, - const std::string& desc, - bool req, - Constraint* constraint, - CmdLineInterface& parser, - bool ignoreable = false, - Visitor* v = NULL ); + /** + * Constructor. + * \param name - The name of the Arg. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param parser - A CmdLine parser object to add this Arg to + * \param ignoreable - Whether or not this argument can be ignored + * using the "--" flag. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + UnlabeledMultiArg( const std::string& name, + const std::string& desc, + bool req, + Constraint* constraint, + CmdLineInterface& parser, + bool ignoreable = false, + Visitor* v = NULL ); - /** - * Handles the processing of the argument. - * This re-implements the Arg version of this method to set the - * _value of the argument appropriately. It knows the difference - * between labeled and unlabeled. - * \param i - Pointer the the current argument in the list. - * \param args - Mutable list of strings. Passed from main(). - */ - virtual bool processArg(int* i, std::vector& args); + /** + * Handles the processing of the argument. + * This re-implements the Arg version of this method to set the + * _value of the argument appropriately. It knows the difference + * between labeled and unlabeled. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. Passed from main(). + */ + virtual bool processArg(int* i, std::vector& args); - /** - * Returns the a short id string. Used in the usage. - * \param val - value to be used. - */ - virtual std::string shortID(const std::string& val="val") const; + /** + * Returns the a short id string. Used in the usage. + * \param val - value to be used. + */ + virtual std::string shortID(const std::string& val="val") const; - /** - * Returns the a long id string. Used in the usage. - * \param val - value to be used. - */ - virtual std::string longID(const std::string& val="val") const; + /** + * Returns the a long id string. Used in the usage. + * \param val - value to be used. + */ + virtual std::string longID(const std::string& val="val") const; - /** - * Opertor ==. - * \param a - The Arg to be compared to this. - */ - virtual bool operator==(const Arg& a) const; + /** + * Opertor ==. + * \param a - The Arg to be compared to this. + */ + virtual bool operator==(const Arg& a) const; - /** - * Pushes this to back of list rather than front. - * \param argList - The list this should be added to. - */ - virtual void addToList( std::list& argList ) const; + /** + * Pushes this to back of list rather than front. + * \param argList - The list this should be added to. + */ + virtual void addToList( std::list& argList ) const; }; template UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, - const std::string& desc, - bool req, - const std::string& typeDesc, - bool ignoreable, - Visitor* v) -: MultiArg("", name, desc, req, typeDesc, v) + const std::string& desc, + bool req, + const std::string& typeDesc, + bool ignoreable, + Visitor* v) + : MultiArg("", name, desc, req, typeDesc, v) { - _ignoreable = ignoreable; - OptionalUnlabeledTracker::check(true, toString()); + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(true, toString()); } template UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, - const std::string& desc, - bool req, - const std::string& typeDesc, - CmdLineInterface& parser, - bool ignoreable, - Visitor* v) -: MultiArg("", name, desc, req, typeDesc, v) + const std::string& desc, + bool req, + const std::string& typeDesc, + CmdLineInterface& parser, + bool ignoreable, + Visitor* v) + : MultiArg("", name, desc, req, typeDesc, v) { - _ignoreable = ignoreable; - OptionalUnlabeledTracker::check(true, toString()); - parser.add( this ); + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(true, toString()); + parser.add( this ); } template UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, - const std::string& desc, - bool req, - Constraint* constraint, - bool ignoreable, - Visitor* v) -: MultiArg("", name, desc, req, constraint, v) + const std::string& desc, + bool req, + Constraint* constraint, + bool ignoreable, + Visitor* v) + : MultiArg("", name, desc, req, constraint, v) { - _ignoreable = ignoreable; - OptionalUnlabeledTracker::check(true, toString()); + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(true, toString()); } template UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, - const std::string& desc, - bool req, - Constraint* constraint, - CmdLineInterface& parser, - bool ignoreable, - Visitor* v) -: MultiArg("", name, desc, req, constraint, v) + const std::string& desc, + bool req, + Constraint* constraint, + CmdLineInterface& parser, + bool ignoreable, + Visitor* v) + : MultiArg("", name, desc, req, constraint, v) { - _ignoreable = ignoreable; - OptionalUnlabeledTracker::check(true, toString()); - parser.add( this ); + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(true, toString()); + parser.add( this ); } template bool UnlabeledMultiArg::processArg(int *i, std::vector& args) { - - if ( _hasBlanks( args[*i] ) ) - return false; - - // never ignore an unlabeled multi arg - - - // always take the first value, regardless of the start string - _extractValue( args[(*i)] ); - - /* - // continue taking args until we hit the end or a start string - while ( (unsigned int)(*i)+1 < args.size() && - args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 && + if ( _hasBlanks( args[*i] ) ) + return false; + // never ignore an unlabeled multi arg + // always take the first value, regardless of the start string + _extractValue( args[(*i)] ); + /* + // continue taking args until we hit the end or a start string + while ( (unsigned int)(*i)+1 < args.size() && + args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 && args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) - _extractValue( args[++(*i)] ); - */ - - _alreadySet = true; - - return true; + _extractValue( args[++(*i)] ); + */ + _alreadySet = true; + return true; } template std::string UnlabeledMultiArg::shortID(const std::string& val) const { - static_cast(val); // Ignore input, don't warn - return std::string("<") + _typeDesc + "> ..."; + static_cast(val); // Ignore input, don't warn + return std::string("<") + _typeDesc + "> ..."; } template std::string UnlabeledMultiArg::longID(const std::string& val) const { - static_cast(val); // Ignore input, don't warn - return std::string("<") + _typeDesc + "> (accepted multiple times)"; + static_cast(val); // Ignore input, don't warn + return std::string("<") + _typeDesc + "> (accepted multiple times)"; } template bool UnlabeledMultiArg::operator==(const Arg& a) const { - if ( _name == a.getName() || _description == a.getDescription() ) - return true; - else - return false; + if ( _name == a.getName() || _description == a.getDescription() ) + return true; + else + return false; } template void UnlabeledMultiArg::addToList( std::list& argList ) const { - argList.push_back( const_cast(static_cast(this)) ); + argList.push_back( const_cast(static_cast(this)) ); } } diff --git a/src/tclap/UnlabeledValueArg.h b/src/tclap/UnlabeledValueArg.h index fcf6401..8e2f32b 100644 --- a/src/tclap/UnlabeledValueArg.h +++ b/src/tclap/UnlabeledValueArg.h @@ -31,7 +31,8 @@ #include "OptionalUnlabeledTracker.h" -namespace TCLAP { +namespace TCLAP +{ /** * The basic unlabeled argument that parses a value. @@ -43,166 +44,166 @@ template class UnlabeledValueArg : public ValueArg { - // If compiler has two stage name lookup (as gcc >= 3.4 does) - // this is requried to prevent undef. symbols - using ValueArg::_ignoreable; - using ValueArg::_hasBlanks; - using ValueArg::_extractValue; - using ValueArg::_typeDesc; - using ValueArg::_name; - using ValueArg::_description; - using ValueArg::_alreadySet; - using ValueArg::toString; + // If compiler has two stage name lookup (as gcc >= 3.4 does) + // this is requried to prevent undef. symbols + using ValueArg::_ignoreable; + using ValueArg::_hasBlanks; + using ValueArg::_extractValue; + using ValueArg::_typeDesc; + using ValueArg::_name; + using ValueArg::_description; + using ValueArg::_alreadySet; + using ValueArg::toString; - public: + public: - /** - * UnlabeledValueArg constructor. - * \param name - A one word name for the argument. Note that this is used for - * identification, not as a long flag. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param value - The default value assigned to this argument if it - * is not present on the command line. - * \param typeDesc - A short, human readable description of the - * type that this object expects. This is used in the generation - * of the USAGE statement. The goal is to be helpful to the end user - * of the program. - * \param ignoreable - Allows you to specify that this argument can be - * ignored if the '--' flag is set. This defaults to false (cannot - * be ignored) and should generally stay that way unless you have - * some special need for certain arguments to be ignored. - * \param v - Optional Vistor. You should leave this blank unless - * you have a very good reason. - */ - UnlabeledValueArg( const std::string& name, - const std::string& desc, - bool req, - T value, - const std::string& typeDesc, - bool ignoreable = false, - Visitor* v = NULL); + /** + * UnlabeledValueArg constructor. + * \param name - A one word name for the argument. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param ignoreable - Allows you to specify that this argument can be + * ignored if the '--' flag is set. This defaults to false (cannot + * be ignored) and should generally stay that way unless you have + * some special need for certain arguments to be ignored. + * \param v - Optional Vistor. You should leave this blank unless + * you have a very good reason. + */ + UnlabeledValueArg( const std::string& name, + const std::string& desc, + bool req, + T value, + const std::string& typeDesc, + bool ignoreable = false, + Visitor* v = NULL); - /** - * UnlabeledValueArg constructor. - * \param name - A one word name for the argument. Note that this is used for - * identification, not as a long flag. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param value - The default value assigned to this argument if it - * is not present on the command line. - * \param typeDesc - A short, human readable description of the - * type that this object expects. This is used in the generation - * of the USAGE statement. The goal is to be helpful to the end user - * of the program. - * \param parser - A CmdLine parser object to add this Arg to - * \param ignoreable - Allows you to specify that this argument can be - * ignored if the '--' flag is set. This defaults to false (cannot - * be ignored) and should generally stay that way unless you have - * some special need for certain arguments to be ignored. - * \param v - Optional Vistor. You should leave this blank unless - * you have a very good reason. - */ - UnlabeledValueArg( const std::string& name, - const std::string& desc, - bool req, - T value, - const std::string& typeDesc, - CmdLineInterface& parser, - bool ignoreable = false, - Visitor* v = NULL ); + /** + * UnlabeledValueArg constructor. + * \param name - A one word name for the argument. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param parser - A CmdLine parser object to add this Arg to + * \param ignoreable - Allows you to specify that this argument can be + * ignored if the '--' flag is set. This defaults to false (cannot + * be ignored) and should generally stay that way unless you have + * some special need for certain arguments to be ignored. + * \param v - Optional Vistor. You should leave this blank unless + * you have a very good reason. + */ + UnlabeledValueArg( const std::string& name, + const std::string& desc, + bool req, + T value, + const std::string& typeDesc, + CmdLineInterface& parser, + bool ignoreable = false, + Visitor* v = NULL ); - /** - * UnlabeledValueArg constructor. - * \param name - A one word name for the argument. Note that this is used for - * identification, not as a long flag. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param value - The default value assigned to this argument if it - * is not present on the command line. - * \param constraint - A pointer to a Constraint object used - * to constrain this Arg. - * \param ignoreable - Allows you to specify that this argument can be - * ignored if the '--' flag is set. This defaults to false (cannot - * be ignored) and should generally stay that way unless you have - * some special need for certain arguments to be ignored. - * \param v - Optional Vistor. You should leave this blank unless - * you have a very good reason. - */ - UnlabeledValueArg( const std::string& name, - const std::string& desc, - bool req, - T value, - Constraint* constraint, - bool ignoreable = false, - Visitor* v = NULL ); + /** + * UnlabeledValueArg constructor. + * \param name - A one word name for the argument. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param ignoreable - Allows you to specify that this argument can be + * ignored if the '--' flag is set. This defaults to false (cannot + * be ignored) and should generally stay that way unless you have + * some special need for certain arguments to be ignored. + * \param v - Optional Vistor. You should leave this blank unless + * you have a very good reason. + */ + UnlabeledValueArg( const std::string& name, + const std::string& desc, + bool req, + T value, + Constraint* constraint, + bool ignoreable = false, + Visitor* v = NULL ); - /** - * UnlabeledValueArg constructor. - * \param name - A one word name for the argument. Note that this is used for - * identification, not as a long flag. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param value - The default value assigned to this argument if it - * is not present on the command line. - * \param constraint - A pointer to a Constraint object used - * to constrain this Arg. - * \param parser - A CmdLine parser object to add this Arg to - * \param ignoreable - Allows you to specify that this argument can be - * ignored if the '--' flag is set. This defaults to false (cannot - * be ignored) and should generally stay that way unless you have - * some special need for certain arguments to be ignored. - * \param v - Optional Vistor. You should leave this blank unless - * you have a very good reason. - */ - UnlabeledValueArg( const std::string& name, - const std::string& desc, - bool req, - T value, - Constraint* constraint, - CmdLineInterface& parser, - bool ignoreable = false, - Visitor* v = NULL); + /** + * UnlabeledValueArg constructor. + * \param name - A one word name for the argument. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param parser - A CmdLine parser object to add this Arg to + * \param ignoreable - Allows you to specify that this argument can be + * ignored if the '--' flag is set. This defaults to false (cannot + * be ignored) and should generally stay that way unless you have + * some special need for certain arguments to be ignored. + * \param v - Optional Vistor. You should leave this blank unless + * you have a very good reason. + */ + UnlabeledValueArg( const std::string& name, + const std::string& desc, + bool req, + T value, + Constraint* constraint, + CmdLineInterface& parser, + bool ignoreable = false, + Visitor* v = NULL); - /** - * Handles the processing of the argument. - * This re-implements the Arg version of this method to set the - * _value of the argument appropriately. Handling specific to - * unlabled arguments. - * \param i - Pointer the the current argument in the list. - * \param args - Mutable list of strings. - */ - virtual bool processArg(int* i, std::vector& args); + /** + * Handles the processing of the argument. + * This re-implements the Arg version of this method to set the + * _value of the argument appropriately. Handling specific to + * unlabled arguments. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. + */ + virtual bool processArg(int* i, std::vector& args); - /** - * Overrides shortID for specific behavior. - */ - virtual std::string shortID(const std::string& val="val") const; + /** + * Overrides shortID for specific behavior. + */ + virtual std::string shortID(const std::string& val="val") const; - /** - * Overrides longID for specific behavior. - */ - virtual std::string longID(const std::string& val="val") const; + /** + * Overrides longID for specific behavior. + */ + virtual std::string longID(const std::string& val="val") const; - /** - * Overrides operator== for specific behavior. - */ - virtual bool operator==(const Arg& a ) const; + /** + * Overrides operator== for specific behavior. + */ + virtual bool operator==(const Arg& a ) const; - /** - * Instead of pushing to the front of list, push to the back. - * \param argList - The list to add this to. - */ - virtual void addToList( std::list& argList ) const; + /** + * Instead of pushing to the front of list, push to the back. + * \param argList - The list to add this to. + */ + virtual void addToList( std::list& argList ) const; }; @@ -211,34 +212,32 @@ class UnlabeledValueArg : public ValueArg */ template UnlabeledValueArg::UnlabeledValueArg(const std::string& name, - const std::string& desc, - bool req, - T val, - const std::string& typeDesc, - bool ignoreable, - Visitor* v) -: ValueArg("", name, desc, req, val, typeDesc, v) + const std::string& desc, + bool req, + T val, + const std::string& typeDesc, + bool ignoreable, + Visitor* v) + : ValueArg("", name, desc, req, val, typeDesc, v) { - _ignoreable = ignoreable; - - OptionalUnlabeledTracker::check(req, toString()); - + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(req, toString()); } template UnlabeledValueArg::UnlabeledValueArg(const std::string& name, - const std::string& desc, - bool req, - T val, - const std::string& typeDesc, - CmdLineInterface& parser, - bool ignoreable, - Visitor* v) -: ValueArg("", name, desc, req, val, typeDesc, v) + const std::string& desc, + bool req, + T val, + const std::string& typeDesc, + CmdLineInterface& parser, + bool ignoreable, + Visitor* v) + : ValueArg("", name, desc, req, val, typeDesc, v) { - _ignoreable = ignoreable; - OptionalUnlabeledTracker::check(req, toString()); - parser.add( this ); + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(req, toString()); + parser.add( this ); } /** @@ -247,31 +246,31 @@ UnlabeledValueArg::UnlabeledValueArg(const std::string& name, template UnlabeledValueArg::UnlabeledValueArg(const std::string& name, const std::string& desc, - bool req, + bool req, T val, Constraint* constraint, bool ignoreable, Visitor* v) -: ValueArg("", name, desc, req, val, constraint, v) + : ValueArg("", name, desc, req, val, constraint, v) { - _ignoreable = ignoreable; - OptionalUnlabeledTracker::check(req, toString()); + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(req, toString()); } template UnlabeledValueArg::UnlabeledValueArg(const std::string& name, - const std::string& desc, - bool req, - T val, - Constraint* constraint, - CmdLineInterface& parser, - bool ignoreable, - Visitor* v) -: ValueArg("", name, desc, req, val, constraint, v) + const std::string& desc, + bool req, + T val, + Constraint* constraint, + CmdLineInterface& parser, + bool ignoreable, + Visitor* v) + : ValueArg("", name, desc, req, val, constraint, v) { - _ignoreable = ignoreable; - OptionalUnlabeledTracker::check(req, toString()); - parser.add( this ); + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(req, toString()); + parser.add( this ); } /** @@ -280,18 +279,14 @@ UnlabeledValueArg::UnlabeledValueArg(const std::string& name, template bool UnlabeledValueArg::processArg(int *i, std::vector& args) { - - if ( _alreadySet ) - return false; - - if ( _hasBlanks( args[*i] ) ) - return false; - - // never ignore an unlabeled arg - - _extractValue( args[*i] ); - _alreadySet = true; - return true; + if ( _alreadySet ) + return false; + if ( _hasBlanks( args[*i] ) ) + return false; + // never ignore an unlabeled arg + _extractValue( args[*i] ); + _alreadySet = true; + return true; } /** @@ -300,8 +295,8 @@ bool UnlabeledValueArg::processArg(int *i, std::vector& args) template std::string UnlabeledValueArg::shortID(const std::string& val) const { - static_cast(val); // Ignore input, don't warn - return std::string("<") + _typeDesc + ">"; + static_cast(val); // Ignore input, don't warn + return std::string("<") + _typeDesc + ">"; } /** @@ -310,12 +305,11 @@ std::string UnlabeledValueArg::shortID(const std::string& val) const template std::string UnlabeledValueArg::longID(const std::string& val) const { - static_cast(val); // Ignore input, don't warn - - // Ideally we would like to be able to use RTTI to return the name - // of the type required for this argument. However, g++ at least, - // doesn't appear to return terribly useful "names" of the types. - return std::string("<") + _typeDesc + ">"; + static_cast(val); // Ignore input, don't warn + // Ideally we would like to be able to use RTTI to return the name + // of the type required for this argument. However, g++ at least, + // doesn't appear to return terribly useful "names" of the types. + return std::string("<") + _typeDesc + ">"; } /** @@ -324,16 +318,16 @@ std::string UnlabeledValueArg::longID(const std::string& val) const template bool UnlabeledValueArg::operator==(const Arg& a ) const { - if ( _name == a.getName() || _description == a.getDescription() ) - return true; - else - return false; + if ( _name == a.getName() || _description == a.getDescription() ) + return true; + else + return false; } template void UnlabeledValueArg::addToList( std::list& argList ) const { - argList.push_back( const_cast(static_cast(this)) ); + argList.push_back( const_cast(static_cast(this)) ); } } diff --git a/src/tclap/ValueArg.h b/src/tclap/ValueArg.h index bdf7f9c..9634b1e 100644 --- a/src/tclap/ValueArg.h +++ b/src/tclap/ValueArg.h @@ -29,7 +29,8 @@ #include "Arg.h" #include "Constraint.h" -namespace TCLAP { +namespace TCLAP +{ /** * The basic labeled argument that parses a value. @@ -42,206 +43,206 @@ namespace TCLAP { template class ValueArg : public Arg { - protected: + protected: - /** - * The value parsed from the command line. - * Can be of any type, as long as the >> operator for the type - * is defined. - */ - T _value; + /** + * The value parsed from the command line. + * Can be of any type, as long as the >> operator for the type + * is defined. + */ + T _value; - /** - * Used to support the reset() method so that ValueArg can be - * reset to their constructed value. - */ - T _default; + /** + * Used to support the reset() method so that ValueArg can be + * reset to their constructed value. + */ + T _default; - /** - * A human readable description of the type to be parsed. - * This is a hack, plain and simple. Ideally we would use RTTI to - * return the name of type T, but until there is some sort of - * consistent support for human readable names, we are left to our - * own devices. - */ - std::string _typeDesc; + /** + * A human readable description of the type to be parsed. + * This is a hack, plain and simple. Ideally we would use RTTI to + * return the name of type T, but until there is some sort of + * consistent support for human readable names, we are left to our + * own devices. + */ + std::string _typeDesc; - /** - * A Constraint this Arg must conform to. - */ - Constraint* _constraint; + /** + * A Constraint this Arg must conform to. + */ + Constraint* _constraint; - /** - * Extracts the value from the string. - * Attempts to parse string as type T, if this fails an exception - * is thrown. - * \param val - value to be parsed. - */ - void _extractValue( const std::string& val ); + /** + * Extracts the value from the string. + * Attempts to parse string as type T, if this fails an exception + * is thrown. + * \param val - value to be parsed. + */ + void _extractValue( const std::string& val ); - public: + public: - /** - * Labeled ValueArg constructor. - * You could conceivably call this constructor with a blank flag, - * but that would make you a bad person. It would also cause - * an exception to be thrown. If you want an unlabeled argument, - * use the other constructor. - * \param flag - The one character flag that identifies this - * argument on the command line. - * \param name - A one word name for the argument. Can be - * used as a long flag on the command line. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param value - The default value assigned to this argument if it - * is not present on the command line. - * \param typeDesc - A short, human readable description of the - * type that this object expects. This is used in the generation - * of the USAGE statement. The goal is to be helpful to the end user - * of the program. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - ValueArg( const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, - T value, - const std::string& typeDesc, - Visitor* v = NULL); + /** + * Labeled ValueArg constructor. + * You could conceivably call this constructor with a blank flag, + * but that would make you a bad person. It would also cause + * an exception to be thrown. If you want an unlabeled argument, + * use the other constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + ValueArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + T value, + const std::string& typeDesc, + Visitor* v = NULL); - /** - * Labeled ValueArg constructor. - * You could conceivably call this constructor with a blank flag, - * but that would make you a bad person. It would also cause - * an exception to be thrown. If you want an unlabeled argument, - * use the other constructor. - * \param flag - The one character flag that identifies this - * argument on the command line. - * \param name - A one word name for the argument. Can be - * used as a long flag on the command line. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param value - The default value assigned to this argument if it - * is not present on the command line. - * \param typeDesc - A short, human readable description of the - * type that this object expects. This is used in the generation - * of the USAGE statement. The goal is to be helpful to the end user - * of the program. - * \param parser - A CmdLine parser object to add this Arg to - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - ValueArg( const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, - T value, - const std::string& typeDesc, - CmdLineInterface& parser, - Visitor* v = NULL ); + /** + * Labeled ValueArg constructor. + * You could conceivably call this constructor with a blank flag, + * but that would make you a bad person. It would also cause + * an exception to be thrown. If you want an unlabeled argument, + * use the other constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param parser - A CmdLine parser object to add this Arg to + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + ValueArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + T value, + const std::string& typeDesc, + CmdLineInterface& parser, + Visitor* v = NULL ); - /** - * Labeled ValueArg constructor. - * You could conceivably call this constructor with a blank flag, - * but that would make you a bad person. It would also cause - * an exception to be thrown. If you want an unlabeled argument, - * use the other constructor. - * \param flag - The one character flag that identifies this - * argument on the command line. - * \param name - A one word name for the argument. Can be - * used as a long flag on the command line. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param value - The default value assigned to this argument if it - * is not present on the command line. - * \param constraint - A pointer to a Constraint object used - * to constrain this Arg. - * \param parser - A CmdLine parser object to add this Arg to. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - ValueArg( const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, - T value, - Constraint* constraint, - CmdLineInterface& parser, - Visitor* v = NULL ); + /** + * Labeled ValueArg constructor. + * You could conceivably call this constructor with a blank flag, + * but that would make you a bad person. It would also cause + * an exception to be thrown. If you want an unlabeled argument, + * use the other constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param parser - A CmdLine parser object to add this Arg to. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + ValueArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + T value, + Constraint* constraint, + CmdLineInterface& parser, + Visitor* v = NULL ); - /** - * Labeled ValueArg constructor. - * You could conceivably call this constructor with a blank flag, - * but that would make you a bad person. It would also cause - * an exception to be thrown. If you want an unlabeled argument, - * use the other constructor. - * \param flag - The one character flag that identifies this - * argument on the command line. - * \param name - A one word name for the argument. Can be - * used as a long flag on the command line. - * \param desc - A description of what the argument is for or - * does. - * \param req - Whether the argument is required on the command - * line. - * \param value - The default value assigned to this argument if it - * is not present on the command line. - * \param constraint - A pointer to a Constraint object used - * to constrain this Arg. - * \param v - An optional visitor. You probably should not - * use this unless you have a very good reason. - */ - ValueArg( const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, - T value, - Constraint* constraint, - Visitor* v = NULL ); + /** + * Labeled ValueArg constructor. + * You could conceivably call this constructor with a blank flag, + * but that would make you a bad person. It would also cause + * an exception to be thrown. If you want an unlabeled argument, + * use the other constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + ValueArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + T value, + Constraint* constraint, + Visitor* v = NULL ); - /** - * Handles the processing of the argument. - * This re-implements the Arg version of this method to set the - * _value of the argument appropriately. It knows the difference - * between labeled and unlabeled. - * \param i - Pointer the the current argument in the list. - * \param args - Mutable list of strings. Passed - * in from main(). - */ - virtual bool processArg(int* i, std::vector& args); + /** + * Handles the processing of the argument. + * This re-implements the Arg version of this method to set the + * _value of the argument appropriately. It knows the difference + * between labeled and unlabeled. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. Passed + * in from main(). + */ + virtual bool processArg(int* i, std::vector& args); - /** - * Returns the value of the argument. - */ - T& getValue() ; + /** + * Returns the value of the argument. + */ + T& getValue() ; - /** - * Specialization of shortID. - * \param val - value to be used. - */ - virtual std::string shortID(const std::string& val = "val") const; + /** + * Specialization of shortID. + * \param val - value to be used. + */ + virtual std::string shortID(const std::string& val = "val") const; - /** - * Specialization of longID. - * \param val - value to be used. - */ - virtual std::string longID(const std::string& val = "val") const; + /** + * Specialization of longID. + * \param val - value to be used. + */ + virtual std::string longID(const std::string& val = "val") const; - virtual void reset() ; + virtual void reset() ; -private: - /** - * Prevent accidental copying - */ - ValueArg(const ValueArg& rhs); - ValueArg& operator=(const ValueArg& rhs); + private: + /** + * Prevent accidental copying + */ + ValueArg(const ValueArg& rhs); + ValueArg& operator=(const ValueArg& rhs); }; @@ -256,11 +257,11 @@ ValueArg::ValueArg(const std::string& flag, T val, const std::string& typeDesc, Visitor* v) -: Arg(flag, name, desc, req, true, v), - _value( val ), - _default( val ), - _typeDesc( typeDesc ), - _constraint( NULL ) + : Arg(flag, name, desc, req, true, v), + _value( val ), + _default( val ), + _typeDesc( typeDesc ), + _constraint( NULL ) { } template @@ -272,13 +273,13 @@ ValueArg::ValueArg(const std::string& flag, const std::string& typeDesc, CmdLineInterface& parser, Visitor* v) -: Arg(flag, name, desc, req, true, v), - _value( val ), - _default( val ), - _typeDesc( typeDesc ), - _constraint( NULL ) + : Arg(flag, name, desc, req, true, v), + _value( val ), + _default( val ), + _typeDesc( typeDesc ), + _constraint( NULL ) { - parser.add( this ); + parser.add( this ); } template @@ -289,11 +290,11 @@ ValueArg::ValueArg(const std::string& flag, T val, Constraint* constraint, Visitor* v) -: Arg(flag, name, desc, req, true, v), - _value( val ), - _default( val ), - _typeDesc( constraint->shortID() ), - _constraint( constraint ) + : Arg(flag, name, desc, req, true, v), + _value( val ), + _default( val ), + _typeDesc( constraint->shortID() ), + _constraint( constraint ) { } template @@ -305,13 +306,13 @@ ValueArg::ValueArg(const std::string& flag, Constraint* constraint, CmdLineInterface& parser, Visitor* v) -: Arg(flag, name, desc, req, true, v), - _value( val ), - _default( val ), - _typeDesc( constraint->shortID() ), - _constraint( constraint ) + : Arg(flag, name, desc, req, true, v), + _value( val ), + _default( val ), + _typeDesc( constraint->shortID() ), + _constraint( constraint ) { - parser.add( this ); + parser.add( this ); } @@ -319,7 +320,10 @@ ValueArg::ValueArg(const std::string& flag, * Implementation of getValue(). */ template -T& ValueArg::getValue() { return _value; } +T& ValueArg::getValue() +{ + return _value; +} /** * Implementation of processArg(). @@ -327,53 +331,46 @@ T& ValueArg::getValue() { return _value; } template bool ValueArg::processArg(int *i, std::vector& args) { - if ( _ignoreable && Arg::ignoreRest() ) - return false; - - if ( _hasBlanks( args[*i] ) ) - return false; - - std::string flag = args[*i]; - - std::string value = ""; - trimFlag( flag, value ); - - if ( argMatches( flag ) ) + if ( _ignoreable && Arg::ignoreRest() ) + return false; + if ( _hasBlanks( args[*i] ) ) + return false; + std::string flag = args[*i]; + std::string value = ""; + trimFlag( flag, value ); + if ( argMatches( flag ) ) + { + if ( _alreadySet ) { - if ( _alreadySet ) - { - if ( _xorSet ) - throw( CmdLineParseException( - "Mutually exclusive argument already set!", - toString()) ); - else - throw( CmdLineParseException("Argument already set!", - toString()) ); - } - - if ( Arg::delimiter() != ' ' && value == "" ) - throw( ArgParseException( - "Couldn't find delimiter for this argument!", - toString() ) ); - - if ( value == "" ) - { - (*i)++; - if ( static_cast(*i) < args.size() ) - _extractValue( args[*i] ); - else - throw( ArgParseException("Missing a value for this argument!", - toString() ) ); - } - else - _extractValue( value ); - - _alreadySet = true; - _checkWithVisitor(); - return true; + if ( _xorSet ) + throw( CmdLineParseException( + "Mutually exclusive argument already set!", + toString()) ); + else + throw( CmdLineParseException("Argument already set!", + toString()) ); + } + if ( Arg::delimiter() != ' ' && value == "" ) + throw( ArgParseException( + "Couldn't find delimiter for this argument!", + toString() ) ); + if ( value == "" ) + { + (*i)++; + if ( static_cast(*i) < args.size() ) + _extractValue( args[*i] ); + else + throw( ArgParseException("Missing a value for this argument!", + toString() ) ); } else - return false; + _extractValue( value ); + _alreadySet = true; + _checkWithVisitor(); + return true; + } + else + return false; } /** @@ -382,8 +379,8 @@ bool ValueArg::processArg(int *i, std::vector& args) template std::string ValueArg::shortID(const std::string& val) const { - static_cast(val); // Ignore input, don't warn - return Arg::shortID( _typeDesc ); + static_cast(val); // Ignore input, don't warn + return Arg::shortID( _typeDesc ); } /** @@ -392,32 +389,34 @@ std::string ValueArg::shortID(const std::string& val) const template std::string ValueArg::longID(const std::string& val) const { - static_cast(val); // Ignore input, don't warn - return Arg::longID( _typeDesc ); + static_cast(val); // Ignore input, don't warn + return Arg::longID( _typeDesc ); } template void ValueArg::_extractValue( const std::string& val ) { - try { - ExtractValue(_value, val, typename ArgTraits::ValueCategory()); - } catch( ArgParseException &e) { - throw ArgParseException(e.error(), toString()); - } - - if ( _constraint != NULL ) - if ( ! _constraint->check( _value ) ) - throw( CmdLineParseException( "Value '" + val + - + "' does not meet constraint: " - + _constraint->description(), - toString() ) ); + try + { + ExtractValue(_value, val, typename ArgTraits::ValueCategory()); + } + catch( ArgParseException &e) + { + throw ArgParseException(e.error(), toString()); + } + if ( _constraint != NULL ) + if ( ! _constraint->check( _value ) ) + throw( CmdLineParseException( "Value '" + val + + + "' does not meet constraint: " + + _constraint->description(), + toString() ) ); } template void ValueArg::reset() { - Arg::reset(); - _value = _default; + Arg::reset(); + _value = _default; } } // namespace TCLAP diff --git a/src/tclap/ValuesConstraint.h b/src/tclap/ValuesConstraint.h index 835b7bf..9c31276 100644 --- a/src/tclap/ValuesConstraint.h +++ b/src/tclap/ValuesConstraint.h @@ -41,7 +41,8 @@ #error "Need a stringstream (sstream or strstream) to compile!" #endif -namespace TCLAP { +namespace TCLAP +{ /** * A Constraint that constrains the Arg to only those values specified @@ -51,95 +52,91 @@ template class ValuesConstraint : public Constraint { - public: + public: - /** - * Constructor. - * \param allowed - vector of allowed values. - */ - ValuesConstraint(std::vector& allowed); + /** + * Constructor. + * \param allowed - vector of allowed values. + */ + ValuesConstraint(std::vector& allowed); - /** - * Virtual destructor. - */ - virtual ~ValuesConstraint() {} + /** + * Virtual destructor. + */ + virtual ~ValuesConstraint() {} - /** - * Returns a description of the Constraint. - */ - virtual std::string description() const; + /** + * Returns a description of the Constraint. + */ + virtual std::string description() const; - /** - * Returns the short ID for the Constraint. - */ - virtual std::string shortID() const; + /** + * Returns the short ID for the Constraint. + */ + virtual std::string shortID() const; - /** - * The method used to verify that the value parsed from the command - * line meets the constraint. - * \param value - The value that will be checked. - */ - virtual bool check(const T& value) const; + /** + * The method used to verify that the value parsed from the command + * line meets the constraint. + * \param value - The value that will be checked. + */ + virtual bool check(const T& value) const; - protected: + protected: - /** - * The list of valid values. - */ - std::vector _allowed; + /** + * The list of valid values. + */ + std::vector _allowed; - /** - * The string used to describe the allowed values of this constraint. - */ - std::string _typeDesc; + /** + * The string used to describe the allowed values of this constraint. + */ + std::string _typeDesc; }; template ValuesConstraint::ValuesConstraint(std::vector& allowed) -: _allowed(allowed), - _typeDesc("") + : _allowed(allowed), + _typeDesc("") { - for ( unsigned int i = 0; i < _allowed.size(); i++ ) - { - + for ( unsigned int i = 0; i < _allowed.size(); i++ ) + { #if defined(HAVE_SSTREAM) - std::ostringstream os; + std::ostringstream os; #elif defined(HAVE_STRSTREAM) - std::ostrstream os; + std::ostrstream os; #else #error "Need a stringstream (sstream or strstream) to compile!" #endif - - os << _allowed[i]; - - std::string temp( os.str() ); - - if ( i > 0 ) - _typeDesc += "|"; - _typeDesc += temp; - } + os << _allowed[i]; + std::string temp( os.str() ); + if ( i > 0 ) + _typeDesc += "|"; + _typeDesc += temp; + } } template bool ValuesConstraint::check( const T& val ) const { - if ( std::find(_allowed.begin(),_allowed.end(),val) == _allowed.end() ) - return false; - else - return true; + if ( std::find(_allowed.begin(),_allowed.end(),val) == _allowed.end() ) + return false; + else + return true; } template std::string ValuesConstraint::shortID() const { - return _typeDesc; + return _typeDesc; } template std::string ValuesConstraint::description() const { - return _typeDesc; + return _typeDesc; } diff --git a/src/tclap/VersionVisitor.h b/src/tclap/VersionVisitor.h index b7ab87d..0c94782 100644 --- a/src/tclap/VersionVisitor.h +++ b/src/tclap/VersionVisitor.h @@ -28,7 +28,8 @@ #include "CmdLineOutput.h" #include "Visitor.h" -namespace TCLAP { +namespace TCLAP +{ /** * A Vistor that will call the version method of the given CmdLineOutput @@ -36,43 +37,44 @@ namespace TCLAP { */ class VersionVisitor: public Visitor { - private: - /** - * Prevent accidental copying - */ - VersionVisitor(const VersionVisitor& rhs); - VersionVisitor& operator=(const VersionVisitor& rhs); + private: + /** + * Prevent accidental copying + */ + VersionVisitor(const VersionVisitor& rhs); + VersionVisitor& operator=(const VersionVisitor& rhs); - protected: + protected: - /** - * The CmdLine of interest. - */ - CmdLineInterface* _cmd; + /** + * The CmdLine of interest. + */ + CmdLineInterface* _cmd; - /** - * The output object. - */ - CmdLineOutput** _out; + /** + * The output object. + */ + CmdLineOutput** _out; - public: + public: - /** - * Constructor. - * \param cmd - The CmdLine the output is generated for. - * \param out - The type of output. - */ - VersionVisitor( CmdLineInterface* cmd, CmdLineOutput** out ) - : Visitor(), _cmd( cmd ), _out( out ) { } + /** + * Constructor. + * \param cmd - The CmdLine the output is generated for. + * \param out - The type of output. + */ + VersionVisitor( CmdLineInterface* cmd, CmdLineOutput** out ) + : Visitor(), _cmd( cmd ), _out( out ) { } - /** - * Calls the version method of the output object using the - * specified CmdLine. - */ - void visit() { - (*_out)->version(*_cmd); - throw ExitException(0); - } + /** + * Calls the version method of the output object using the + * specified CmdLine. + */ + void visit() + { + (*_out)->version(*_cmd); + throw ExitException(0); + } }; diff --git a/src/tclap/Visitor.h b/src/tclap/Visitor.h index 2ef79f2..f816acd 100644 --- a/src/tclap/Visitor.h +++ b/src/tclap/Visitor.h @@ -23,29 +23,30 @@ #ifndef TCLAP_VISITOR_H #define TCLAP_VISITOR_H -namespace TCLAP { +namespace TCLAP +{ /** * A base class that defines the interface for visitors. */ class Visitor { - public: + public: - /** - * Constructor. Does nothing. - */ - Visitor() { } + /** + * Constructor. Does nothing. + */ + Visitor() { } - /** - * Destructor. Does nothing. - */ - virtual ~Visitor() { } + /** + * Destructor. Does nothing. + */ + virtual ~Visitor() { } - /** - * Does nothing. Should be overridden by child. - */ - virtual void visit() { } + /** + * Does nothing. Should be overridden by child. + */ + virtual void visit() { } }; } diff --git a/src/tclap/XorHandler.h b/src/tclap/XorHandler.h index 2727f27..9498bc5 100644 --- a/src/tclap/XorHandler.h +++ b/src/tclap/XorHandler.h @@ -29,7 +29,8 @@ #include #include -namespace TCLAP { +namespace TCLAP +{ /** * This class handles lists of Arg's that are to be XOR'd on the command @@ -37,54 +38,54 @@ namespace TCLAP { */ class XorHandler { - protected: + protected: - /** - * The list of of lists of Arg's to be or'd together. - */ - std::vector< std::vector > _orList; + /** + * The list of of lists of Arg's to be or'd together. + */ + std::vector< std::vector > _orList; - public: + public: - /** - * Constructor. Does nothing. - */ - XorHandler( ) : _orList(std::vector< std::vector >()) {} + /** + * Constructor. Does nothing. + */ + XorHandler( ) : _orList(std::vector< std::vector >()) {} - /** - * Add a list of Arg*'s that will be orred together. - * \param ors - list of Arg* that will be xor'd. - */ - void add( std::vector& ors ); + /** + * Add a list of Arg*'s that will be orred together. + * \param ors - list of Arg* that will be xor'd. + */ + void add( std::vector& ors ); - /** - * Checks whether the specified Arg is in one of the xor lists and - * if it does match one, returns the size of the xor list that the - * Arg matched. If the Arg matches, then it also sets the rest of - * the Arg's in the list. You shouldn't use this. - * \param a - The Arg to be checked. - */ - int check( const Arg* a ); + /** + * Checks whether the specified Arg is in one of the xor lists and + * if it does match one, returns the size of the xor list that the + * Arg matched. If the Arg matches, then it also sets the rest of + * the Arg's in the list. You shouldn't use this. + * \param a - The Arg to be checked. + */ + int check( const Arg* a ); - /** - * Returns the XOR specific short usage. - */ - std::string shortUsage(); + /** + * Returns the XOR specific short usage. + */ + std::string shortUsage(); - /** - * Prints the XOR specific long usage. - * \param os - Stream to print to. - */ - void printLongUsage(std::ostream& os); + /** + * Prints the XOR specific long usage. + * \param os - Stream to print to. + */ + void printLongUsage(std::ostream& os); - /** - * Simply checks whether the Arg is contained in one of the arg - * lists. - * \param a - The Arg to be checked. - */ - bool contains( const Arg* a ); + /** + * Simply checks whether the Arg is contained in one of the arg + * lists. + * \param a - The Arg to be checked. + */ + bool contains( const Arg* a ); - std::vector< std::vector >& getXorList(); + std::vector< std::vector >& getXorList(); }; @@ -94,65 +95,61 @@ class XorHandler ////////////////////////////////////////////////////////////////////// inline void XorHandler::add( std::vector& ors ) { - _orList.push_back( ors ); + _orList.push_back( ors ); } inline int XorHandler::check( const Arg* a ) { - // iterate over each XOR list - for ( int i = 0; static_cast(i) < _orList.size(); i++ ) - { - // if the XOR list contains the arg.. - ArgVectorIterator ait = std::find( _orList[i].begin(), - _orList[i].end(), a ); - if ( ait != _orList[i].end() ) - { - // first check to see if a mutually exclusive switch - // has not already been set - for ( ArgVectorIterator it = _orList[i].begin(); - it != _orList[i].end(); - it++ ) - if ( a != (*it) && (*it)->isSet() ) - throw(CmdLineParseException( - "Mutually exclusive argument already set!", - (*it)->toString())); - - // go through and set each arg that is not a - for ( ArgVectorIterator it = _orList[i].begin(); - it != _orList[i].end(); - it++ ) - if ( a != (*it) ) - (*it)->xorSet(); - - // return the number of required args that have now been set - if ( (*ait)->allowMore() ) - return 0; - else - return static_cast(_orList[i].size()); - } - } - - if ( a->isRequired() ) - return 1; - else - return 0; + // iterate over each XOR list + for ( int i = 0; static_cast(i) < _orList.size(); i++ ) + { + // if the XOR list contains the arg.. + ArgVectorIterator ait = std::find( _orList[i].begin(), + _orList[i].end(), a ); + if ( ait != _orList[i].end() ) + { + // first check to see if a mutually exclusive switch + // has not already been set + for ( ArgVectorIterator it = _orList[i].begin(); + it != _orList[i].end(); + it++ ) + if ( a != (*it) && (*it)->isSet() ) + throw(CmdLineParseException( + "Mutually exclusive argument already set!", + (*it)->toString())); + // go through and set each arg that is not a + for ( ArgVectorIterator it = _orList[i].begin(); + it != _orList[i].end(); + it++ ) + if ( a != (*it) ) + (*it)->xorSet(); + // return the number of required args that have now been set + if ( (*ait)->allowMore() ) + return 0; + else + return static_cast(_orList[i].size()); + } + } + if ( a->isRequired() ) + return 1; + else + return 0; } inline bool XorHandler::contains( const Arg* a ) { - for ( int i = 0; static_cast(i) < _orList.size(); i++ ) - for ( ArgVectorIterator it = _orList[i].begin(); - it != _orList[i].end(); - it++ ) - if ( a == (*it) ) - return true; - - return false; + for ( int i = 0; static_cast(i) < _orList.size(); i++ ) + for ( ArgVectorIterator it = _orList[i].begin(); + it != _orList[i].end(); + it++ ) + if ( a == (*it) ) + return true; + return false; } inline std::vector< std::vector >& XorHandler::getXorList() { - return _orList; + return _orList; } diff --git a/src/tclap/ZshCompletionOutput.h b/src/tclap/ZshCompletionOutput.h index e2a36ca..acd6320 100644 --- a/src/tclap/ZshCompletionOutput.h +++ b/src/tclap/ZshCompletionOutput.h @@ -34,7 +34,8 @@ #include #include -namespace TCLAP { +namespace TCLAP +{ /** * A class that generates a Zsh completion function as output from the usage() @@ -43,280 +44,266 @@ namespace TCLAP { class ZshCompletionOutput : public CmdLineOutput { - public: + public: - ZshCompletionOutput(); + ZshCompletionOutput(); - /** - * Prints the usage to stdout. Can be overridden to - * produce alternative behavior. - * \param c - The CmdLine object the output is generated for. - */ - virtual void usage(CmdLineInterface& c); + /** + * Prints the usage to stdout. Can be overridden to + * produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void usage(CmdLineInterface& c); - /** - * Prints the version to stdout. Can be overridden - * to produce alternative behavior. - * \param c - The CmdLine object the output is generated for. - */ - virtual void version(CmdLineInterface& c); + /** + * Prints the version to stdout. Can be overridden + * to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void version(CmdLineInterface& c); - /** - * Prints (to stderr) an error message, short usage - * Can be overridden to produce alternative behavior. - * \param c - The CmdLine object the output is generated for. - * \param e - The ArgException that caused the failure. - */ - virtual void failure(CmdLineInterface& c, - ArgException& e ); + /** + * Prints (to stderr) an error message, short usage + * Can be overridden to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. + */ + virtual void failure(CmdLineInterface& c, + ArgException& e ); - protected: + protected: - void basename( std::string& s ); - void quoteSpecialChars( std::string& s ); + void basename( std::string& s ); + void quoteSpecialChars( std::string& s ); - std::string getMutexList( CmdLineInterface& _cmd, Arg* a ); - void printOption( Arg* it, std::string mutex ); - void printArg( Arg* it ); + std::string getMutexList( CmdLineInterface& _cmd, Arg* a ); + void printOption( Arg* it, std::string mutex ); + void printArg( Arg* it ); - std::map common; - char theDelimiter; + std::map common; + char theDelimiter; }; ZshCompletionOutput::ZshCompletionOutput() -: common(std::map()), - theDelimiter('=') + : common(std::map()), + theDelimiter('=') { - common["host"] = "_hosts"; - common["hostname"] = "_hosts"; - common["file"] = "_files"; - common["filename"] = "_files"; - common["user"] = "_users"; - common["username"] = "_users"; - common["directory"] = "_directories"; - common["path"] = "_directories"; - common["url"] = "_urls"; + common["host"] = "_hosts"; + common["hostname"] = "_hosts"; + common["file"] = "_files"; + common["filename"] = "_files"; + common["user"] = "_users"; + common["username"] = "_users"; + common["directory"] = "_directories"; + common["path"] = "_directories"; + common["url"] = "_urls"; } inline void ZshCompletionOutput::version(CmdLineInterface& _cmd) { - std::cout << _cmd.getVersion() << std::endl; + std::cout << _cmd.getVersion() << std::endl; } inline void ZshCompletionOutput::usage(CmdLineInterface& _cmd ) { - std::list argList = _cmd.getArgList(); - std::string progName = _cmd.getProgramName(); - std::string xversion = _cmd.getVersion(); - theDelimiter = _cmd.getDelimiter(); - basename(progName); - - std::cout << "#compdef " << progName << std::endl << std::endl << - "# " << progName << " version " << _cmd.getVersion() << std::endl << std::endl << - "_arguments -s -S"; - - for (ArgListIterator it = argList.begin(); it != argList.end(); it++) - { - if ( (*it)->shortID().at(0) == '<' ) - printArg((*it)); - else if ( (*it)->getFlag() != "-" ) - printOption((*it), getMutexList(_cmd, *it)); - } - - std::cout << std::endl; + std::list argList = _cmd.getArgList(); + std::string progName = _cmd.getProgramName(); + std::string xversion = _cmd.getVersion(); + theDelimiter = _cmd.getDelimiter(); + basename(progName); + std::cout << "#compdef " << progName << std::endl << std::endl << + "# " << progName << " version " << _cmd.getVersion() << std::endl << std::endl << + "_arguments -s -S"; + for (ArgListIterator it = argList.begin(); it != argList.end(); it++) + { + if ( (*it)->shortID().at(0) == '<' ) + printArg((*it)); + else if ( (*it)->getFlag() != "-" ) + printOption((*it), getMutexList(_cmd, *it)); + } + std::cout << std::endl; } inline void ZshCompletionOutput::failure( CmdLineInterface& _cmd, - ArgException& e ) + ArgException& e ) { - static_cast(_cmd); // unused - std::cout << e.what() << std::endl; + static_cast(_cmd); // unused + std::cout << e.what() << std::endl; } inline void ZshCompletionOutput::quoteSpecialChars( std::string& s ) { - size_t idx = s.find_last_of(':'); - while ( idx != std::string::npos ) - { - s.insert(idx, 1, '\\'); - idx = s.find_last_of(':', idx); - } - idx = s.find_last_of('\''); - while ( idx != std::string::npos ) - { - s.insert(idx, "'\\'"); - if (idx == 0) - idx = std::string::npos; - else - idx = s.find_last_of('\'', --idx); - } + size_t idx = s.find_last_of(':'); + while ( idx != std::string::npos ) + { + s.insert(idx, 1, '\\'); + idx = s.find_last_of(':', idx); + } + idx = s.find_last_of('\''); + while ( idx != std::string::npos ) + { + s.insert(idx, "'\\'"); + if (idx == 0) + idx = std::string::npos; + else + idx = s.find_last_of('\'', --idx); + } } inline void ZshCompletionOutput::basename( std::string& s ) { - size_t p = s.find_last_of('/'); - if ( p != std::string::npos ) - { - s.erase(0, p + 1); - } + size_t p = s.find_last_of('/'); + if ( p != std::string::npos ) + { + s.erase(0, p + 1); + } } inline void ZshCompletionOutput::printArg(Arg* a) { - static int count = 1; - - std::cout << " \\" << std::endl << " '"; - if ( a->acceptsMultipleValues() ) - std::cout << '*'; - else - std::cout << count++; - std::cout << ':'; - if ( !a->isRequired() ) - std::cout << ':'; - - std::cout << a->getName() << ':'; - std::map::iterator compArg = common.find(a->getName()); - if ( compArg != common.end() ) - { - std::cout << compArg->second; - } - else - { - std::cout << "_guard \"^-*\" " << a->getName(); - } - std::cout << '\''; + static int count = 1; + std::cout << " \\" << std::endl << " '"; + if ( a->acceptsMultipleValues() ) + std::cout << '*'; + else + std::cout << count++; + std::cout << ':'; + if ( !a->isRequired() ) + std::cout << ':'; + std::cout << a->getName() << ':'; + std::map::iterator compArg = common.find(a->getName()); + if ( compArg != common.end() ) + { + std::cout << compArg->second; + } + else + { + std::cout << "_guard \"^-*\" " << a->getName(); + } + std::cout << '\''; } inline void ZshCompletionOutput::printOption(Arg* a, std::string mutex) { - std::string flag = a->flagStartChar() + a->getFlag(); - std::string name = a->nameStartString() + a->getName(); - std::string desc = a->getDescription(); - - // remove full stop and capitalisation from description as - // this is the convention for zsh function - if (!desc.compare(0, 12, "(required) ")) - { - desc.erase(0, 12); - } - if (!desc.compare(0, 15, "(OR required) ")) - { - desc.erase(0, 15); - } - size_t len = desc.length(); - if (len && desc.at(--len) == '.') - { - desc.erase(len); - } - if (len) - { - desc.replace(0, 1, 1, tolower(desc.at(0))); - } - - std::cout << " \\" << std::endl << " '" << mutex; - - if ( a->getFlag().empty() ) - { - std::cout << name; - } - else - { - std::cout << "'{" << flag << ',' << name << "}'"; - } - if ( theDelimiter == '=' && a->isValueRequired() ) - std::cout << "=-"; - quoteSpecialChars(desc); - std::cout << '[' << desc << ']'; - - if ( a->isValueRequired() ) - { - std::string arg = a->shortID(); - arg.erase(0, arg.find_last_of(theDelimiter) + 1); - if ( arg.at(arg.length()-1) == ']' ) - arg.erase(arg.length()-1); - if ( arg.at(arg.length()-1) == ']' ) - { - arg.erase(arg.length()-1); - } - if ( arg.at(0) == '<' ) - { - arg.erase(arg.length()-1); - arg.erase(0, 1); - } - size_t p = arg.find('|'); - if ( p != std::string::npos ) - { - do - { - arg.replace(p, 1, 1, ' '); - } - while ( (p = arg.find_first_of('|', p)) != std::string::npos ); - quoteSpecialChars(arg); - std::cout << ": :(" << arg << ')'; - } - else - { - std::cout << ':' << arg; - std::map::iterator compArg = common.find(arg); - if ( compArg != common.end() ) - { - std::cout << ':' << compArg->second; - } - } - } - - std::cout << '\''; + std::string flag = a->flagStartChar() + a->getFlag(); + std::string name = a->nameStartString() + a->getName(); + std::string desc = a->getDescription(); + // remove full stop and capitalisation from description as + // this is the convention for zsh function + if (!desc.compare(0, 12, "(required) ")) + { + desc.erase(0, 12); + } + if (!desc.compare(0, 15, "(OR required) ")) + { + desc.erase(0, 15); + } + size_t len = desc.length(); + if (len && desc.at(--len) == '.') + { + desc.erase(len); + } + if (len) + { + desc.replace(0, 1, 1, tolower(desc.at(0))); + } + std::cout << " \\" << std::endl << " '" << mutex; + if ( a->getFlag().empty() ) + { + std::cout << name; + } + else + { + std::cout << "'{" << flag << ',' << name << "}'"; + } + if ( theDelimiter == '=' && a->isValueRequired() ) + std::cout << "=-"; + quoteSpecialChars(desc); + std::cout << '[' << desc << ']'; + if ( a->isValueRequired() ) + { + std::string arg = a->shortID(); + arg.erase(0, arg.find_last_of(theDelimiter) + 1); + if ( arg.at(arg.length()-1) == ']' ) + arg.erase(arg.length()-1); + if ( arg.at(arg.length()-1) == ']' ) + { + arg.erase(arg.length()-1); + } + if ( arg.at(0) == '<' ) + { + arg.erase(arg.length()-1); + arg.erase(0, 1); + } + size_t p = arg.find('|'); + if ( p != std::string::npos ) + { + do + { + arg.replace(p, 1, 1, ' '); + } + while ( (p = arg.find_first_of('|', p)) != std::string::npos ); + quoteSpecialChars(arg); + std::cout << ": :(" << arg << ')'; + } + else + { + std::cout << ':' << arg; + std::map::iterator compArg = common.find(arg); + if ( compArg != common.end() ) + { + std::cout << ':' << compArg->second; + } + } + } + std::cout << '\''; } inline std::string ZshCompletionOutput::getMutexList( CmdLineInterface& _cmd, Arg* a) { - XorHandler xorHandler = _cmd.getXorHandler(); - std::vector< std::vector > xorList = xorHandler.getXorList(); - - if (a->getName() == "help" || a->getName() == "version") - { - return "(-)"; - } - - std::ostringstream list; - if ( a->acceptsMultipleValues() ) - { - list << '*'; - } - - for ( int i = 0; static_cast(i) < xorList.size(); i++ ) - { - for ( ArgVectorIterator it = xorList[i].begin(); - it != xorList[i].end(); - it++) - if ( a == (*it) ) - { - list << '('; - for ( ArgVectorIterator iu = xorList[i].begin(); - iu != xorList[i].end(); - iu++ ) - { - bool notCur = (*iu) != a; - bool hasFlag = !(*iu)->getFlag().empty(); - if ( iu != xorList[i].begin() && (notCur || hasFlag) ) - list << ' '; - if (hasFlag) - list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' '; - if ( notCur || hasFlag ) - list << (*iu)->nameStartString() << (*iu)->getName(); - } - list << ')'; - return list.str(); - } - } - - // wasn't found in xor list - if (!a->getFlag().empty()) { - list << "(" << a->flagStartChar() << a->getFlag() << ' ' << - a->nameStartString() << a->getName() << ')'; - } - - return list.str(); + XorHandler xorHandler = _cmd.getXorHandler(); + std::vector< std::vector > xorList = xorHandler.getXorList(); + if (a->getName() == "help" || a->getName() == "version") + { + return "(-)"; + } + std::ostringstream list; + if ( a->acceptsMultipleValues() ) + { + list << '*'; + } + for ( int i = 0; static_cast(i) < xorList.size(); i++ ) + { + for ( ArgVectorIterator it = xorList[i].begin(); + it != xorList[i].end(); + it++) + if ( a == (*it) ) + { + list << '('; + for ( ArgVectorIterator iu = xorList[i].begin(); + iu != xorList[i].end(); + iu++ ) + { + bool notCur = (*iu) != a; + bool hasFlag = !(*iu)->getFlag().empty(); + if ( iu != xorList[i].begin() && (notCur || hasFlag) ) + list << ' '; + if (hasFlag) + list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' '; + if ( notCur || hasFlag ) + list << (*iu)->nameStartString() << (*iu)->getName(); + } + list << ')'; + return list.str(); + } + } + // wasn't found in xor list + if (!a->getFlag().empty()) + { + list << "(" << a->flagStartChar() << a->getFlag() << ' ' << + a->nameStartString() << a->getName() << ')'; + } + return list.str(); } } //namespace TCLAP