|
Urbi SDK Remote for C++
2.7.5
|
00001 /* 00002 * Copyright (C) 2009-2011, Gostai S.A.S. 00003 * 00004 * This software is provided "as is" without warranty of any kind, 00005 * either expressed or implied, including but not limited to the 00006 * implied warranties of fitness for a particular purpose. 00007 * 00008 * See the LICENSE file for more information. 00009 */ 00010 00012 00013 #include <iostream> 00014 #include <sstream> 00015 #include <libport/debug.hh> 00016 #include <libport/escape.hh> 00017 #include <libport/foreach.hh> 00018 #include <libport/format.hh> 00019 #include <boost/algorithm/string/trim.hpp> 00020 #include <urbi/ubinary.hh> 00021 #include <urbi/uvalue.hh> // kernelMajor. 00022 00023 GD_CATEGORY(Urbi.UValue); 00024 00025 namespace urbi 00026 { 00027 00028 UBinary::UBinary() 00029 : type(BINARY_NONE) 00030 , allocated_(true) 00031 , temporary_(false) 00032 { 00033 common.data = 0; 00034 common.size = 0; 00035 } 00036 00037 UBinary::UBinary(const UBinary& b, bool copy, bool temp) 00038 : type(BINARY_NONE) 00039 , allocated_(copy) 00040 , temporary_(temp) 00041 { 00042 common.data = 0; 00043 if (copy) 00044 *this = b; 00045 else 00046 { 00047 // Be safe, do not try to guess which is bigger. 00048 image = b.image; 00049 sound = b.sound; 00050 message = b.message; 00051 type = b.type; 00052 } 00053 } 00054 00055 UBinary::UBinary(const UImage& i, bool copy) 00056 : type(BINARY_IMAGE) 00057 , image(i) 00058 , allocated_(copy) 00059 , temporary_(false) 00060 { 00061 if (copy) 00062 { 00063 image.data = static_cast<unsigned char*> (malloc (image.size)); 00064 memcpy(image.data, i.data, image.size); 00065 } 00066 } 00067 00068 UBinary::UBinary(const USound& i, bool copy) 00069 : type(BINARY_SOUND) 00070 , sound(i) 00071 , allocated_(copy) 00072 , temporary_(false) 00073 { 00074 if (copy) 00075 { 00076 sound.data = static_cast<char*> (malloc (sound.size)); 00077 memcpy(sound.data, i.data, sound.size); 00078 } 00079 } 00080 00081 void 00082 UBinary::clear() 00083 { 00084 if (allocated_) 00085 { 00086 free(common.data); 00087 common.data = 0; 00088 common.size = 0; 00089 } 00090 } 00091 00092 UBinary::~UBinary() 00093 { 00094 clear(); 00095 } 00096 00097 UBinary& UBinary::operator= (const UBinary& b) 00098 { 00099 if (this == &b) 00100 return *this; 00101 00102 clear(); 00103 if (b.temporary_) 00104 { 00105 // Be safe, do not try to guess which is bigger. 00106 image = b.image; 00107 sound = b.sound; 00108 message = b.message; 00109 type = b.type; 00110 UBinary& bb = const_cast<UBinary&>(b); 00111 bb.common.data = 0; 00112 bb.type = BINARY_NONE; 00113 temporary_ = true; 00114 return *this; 00115 } 00116 type = b.type; 00117 message = b.message; 00118 common.size = b.common.size; 00119 switch(type) 00120 { 00121 case BINARY_IMAGE: 00122 image = b.image; 00123 break; 00124 case BINARY_SOUND: 00125 sound = b.sound; 00126 break; 00127 case BINARY_NONE: 00128 case BINARY_UNKNOWN: 00129 break; 00130 } 00131 common.data = malloc(common.size); 00132 memcpy(common.data, b.common.data, b.common.size); 00133 return *this; 00134 } 00135 00136 int 00137 UBinary::parse(const char* message, int pos, 00138 const binaries_type& bins, 00139 binaries_type::const_iterator& binpos, bool copy) 00140 { 00141 std::istringstream is(message + pos); 00142 bool ok = parse(is, bins, binpos, copy); 00143 // tellg() might be -1 if we encountered an error. 00144 int endpos = is.tellg(); 00145 if (endpos == -1) 00146 endpos = strlen(message) - pos; 00147 return (ok ? 1:-1) * (pos + endpos); 00148 } 00149 00150 namespace 00151 { 00155 static 00156 std::string 00157 headers_get(std::istringstream& i) 00158 { 00159 std::string res; 00160 int c = 0; 00161 while (!i.eof() 00162 && (c = i.get()) && c != '\n' && c != ';') 00163 res.append(1, c); 00164 if (i.eof()) 00165 GD_ERROR("unexpected end of file while parsing UBinary headers"); 00166 else 00167 { 00168 // Skip the delimiter. 00169 if (c == '\n') 00170 { 00171 if (i.peek() == '\r') 00172 i.ignore(); 00173 } 00174 } 00175 // Remove leading/trailing spaces. 00176 boost::algorithm::trim(res); 00177 return res; 00178 } 00179 } 00180 00181 00182 bool 00183 UBinary::parse(std::istringstream& is, 00184 const binaries_type& bins, 00185 binaries_type::const_iterator& binpos, bool copy) 00186 00187 { 00188 // LIBPORT_ECHO("Parsing: {" << is.str() << "}"); 00189 if (binpos == bins.end()) 00190 { 00191 GD_ERROR("no binary data available"); 00192 return false; 00193 } 00194 00195 // Validate size. 00196 size_t psize; 00197 is >> psize; 00198 if (is.fail()) 00199 { 00200 GD_FERROR("cannot read bin size: %s (%s)", is.str(), psize); 00201 return false; 00202 } 00203 if (psize != binpos->size) 00204 { 00205 GD_FERROR("bin size inconsistency: %s != %s", psize, binpos->size); 00206 return false; 00207 } 00208 common.size = psize; 00209 if (copy) 00210 { 00211 common.data = malloc(common.size); 00212 memcpy(common.data, binpos->data, common.size); 00213 } 00214 else 00215 { 00216 common.data = binpos->data; 00217 this->allocated_ = false; 00218 } 00219 ++binpos; 00220 00221 // Skip spaces. 00222 while (is.peek() == ' ') 00223 is.ignore(); 00224 00225 // Get the headers. 00226 message = headers_get(is); 00227 00228 // Analyse the header to decode know UBinary types. 00229 // Header stream. 00230 std::istringstream hs(message); 00231 00232 // Parse the optional type. Don't check hs.fail, since the type 00233 // is optional, in which case t remains empty. 00234 std::string t; 00235 hs >> t; 00236 UImageFormat image_format = parse_image_format(t); 00237 if (image_format != IMAGE_UNKNOWN || t.find("image_")==0) 00238 { 00239 type = BINARY_IMAGE; 00240 image.size = common.size; 00241 // In some cases (jpeg source), image size is not present in headers. 00242 image.width = image.height = 0; 00243 hs >> image.width >> image.height; 00244 image.imageFormat = image_format; 00245 } 00246 else if (t == "raw" || t == "wav") 00247 { 00248 type = BINARY_SOUND; 00249 sound.soundFormat = parse_sound_format(t); 00250 sound.size = common.size; 00251 hs >> sound.channels 00252 >> sound.rate 00253 >> sound.sampleSize >> sound.sampleFormat; 00254 } 00255 else 00256 { 00257 // GD_FWARN("unknown binary type: %s", t); 00258 type = BINARY_UNKNOWN; 00259 } 00260 00261 return true; 00262 } 00263 00264 void UBinary::buildMessage() 00265 { 00266 message = getMessage(); 00267 } 00268 00269 std::string UBinary::getMessage() const 00270 { 00271 switch (type) 00272 { 00273 case BINARY_IMAGE: 00274 return image.headers_(); 00275 case BINARY_SOUND: 00276 return sound.headers_(); 00277 case BINARY_UNKNOWN: 00278 { 00279 bool warned = false; 00280 std::string res = message; 00281 foreach (char& c, res) 00282 if (c == '\0' || c == '\n' || c == ';') 00283 { 00284 if (!warned) 00285 { 00286 GD_FERROR("invalid UBinary header: " 00287 "prohibited `\\n', `\\0' and `;' will be " 00288 "smashed to space: %s", 00289 libport::escape(message)); 00290 warned = true; 00291 } 00292 c = ' '; 00293 } 00294 // Remove leading/trailing spaces. 00295 boost::algorithm::trim(res); 00296 return res; 00297 } 00298 case BINARY_NONE: 00299 return ""; 00300 } 00301 unreachable(); 00302 } 00303 00304 std::ostream& 00305 UBinary::print(std::ostream& o, int kernelMajor) const 00306 { 00307 if (2 <= kernelMajor) 00308 { 00309 o << libport::format("Global.Binary.new(\"%s\", \"\\B(%s)(", 00310 getMessage(), common.size); 00311 o.write((char*) common.data, common.size); 00312 o << ")\")"; 00313 } 00314 else 00315 { 00316 // Format for the Kernel, which wants ';' as header terminator. 00317 o << "BIN " << common.size; 00318 const std::string h = getMessage(); 00319 if (!h.empty()) 00320 o << ' ' << h; 00321 o << ';'; 00322 o.write((char*) common.data, common.size); 00323 } 00324 return o; 00325 } 00326 00327 std::ostream& 00328 operator<< (std::ostream& o, const UBinary& t) 00329 { 00330 return t.print(o, ::urbi::kernelMajor(o)); 00331 } 00332 00333 } // namespace urbi